diff --git a/onfhir-path/src/main/scala/io/onfhir/path/AbstractFhirPathFunctionLibrary.scala b/onfhir-path/src/main/scala/io/onfhir/path/AbstractFhirPathFunctionLibrary.scala index fceb25ba..0bdbb22c 100644 --- a/onfhir-path/src/main/scala/io/onfhir/path/AbstractFhirPathFunctionLibrary.scala +++ b/onfhir-path/src/main/scala/io/onfhir/path/AbstractFhirPathFunctionLibrary.scala @@ -1,10 +1,11 @@ package io.onfhir.path +import io.onfhir.api.FHIR_DATA_TYPES import io.onfhir.path.grammar.FhirPathExprParser.ExpressionContext import java.lang.reflect.InvocationTargetException +import io.onfhir.path.annotation.{FhirPathFunction, FhirPathFunctionDocumentation, FhirPathFunctionParameter, FhirPathFunctionReturn} -import io.onfhir.path.annotation.FhirPathFunction import scala.reflect.runtime.currentMirror import scala.reflect.runtime.universe._ @@ -18,13 +19,43 @@ abstract class AbstractFhirPathFunctionLibrary { */ def getFunctionSignatures():Seq[(String, Int)] = getClass.getMethods.filterNot(_.getName.startsWith("$anonfun$")).map(m => m.getName -> m.getParameterCount).toSeq + /** + * Method that will be used to call a FHIR Path function from the function library + * Function library should define the function handlers as public methods with the name of the function that gets 0 or more ExpressionContext as parameters and return Seq of FhirPathResult + * + * @param fname Name of the function + * @param params Supplied parameters + * @return + */ + @throws[FhirPathException] + def callFhirPathFunction(fname:String, params:Seq[ExpressionContext]):Seq[FhirPathResult] = { + try { + val method = getClass.getMethod(fname, params.map(_ => classOf[ExpressionContext]): _*) + val result = method.invoke(this, params:_*) + val fhirPathResult = result.asInstanceOf[Seq[FhirPathResult]] + fhirPathResult + } catch { + case n:NoSuchMethodException => + throw new FhirPathException(s"Invalid FHIR Path function call, function $fname does not exist or take ${params.length} arguments !!!") + case ite:InvocationTargetException => + ite.getTargetException match { + case fpe:FhirPathException => throw fpe + case e:Throwable => throw FhirPathException.apply(s"Invalid FHIR Path function call $fname!", e) + } + } + } + /** * Returns documentations of functions in this library. It searches for the methods having FhirPathFunction annotation * and returns them. * * @return a list of FhirPathFunction representing the documentation of functions * */ - def getFunctionDocumentation():Seq[FhirPathFunction] = currentMirror.classSymbol(Class.forName(getClass.getName)) + def getFunctionDocumentation():Seq[FhirPathFunction] = { + var currentFunctionDocumentationField: FhirPathFunctionDocumentation = null + + // Using reflection to inspect the methods annotated with @FhirPathFunction + currentMirror.classSymbol(Class.forName(getClass.getName)) .toType .decls // filter the methods having FhirPathFunction annotation @@ -37,17 +68,26 @@ abstract class AbstractFhirPathFunctionLibrary { .find(_.tree.tpe =:= typeOf[FhirPathFunction]).head .tree.children.tail .collect({ + // Extract documentation details from the annotation + case field if field.tpe.toString.contentEquals("io.onfhir.path.annotation.FhirPathFunctionDocumentation") => + currentFunctionDocumentationField = getFhirPathDocumentation(field); + // matches 'String' fields case Literal(Constant(s: String)) => s + // matches 'Seq[String]' fields case Apply(_: Tree, args: List[Tree]) => args.collect({ // matches 'String's in the sequence case Literal(Constant(s: String)) => s + + case rest => + // matches 'FHIR_DATA_TYPES' fields + getFhirDataTypeValue(rest.toString()) }) }) // create an instance of FhirPathFunction - new FhirPathFunction(documentation = annotationFields.headOption.get.toString, + new FhirPathFunction(documentation = currentFunctionDocumentationField, insertText = annotationFields.lift(1).get.toString, detail = annotationFields.lift(2).get.toString, label = annotationFields.lift(3).get.toString, @@ -55,30 +95,166 @@ abstract class AbstractFhirPathFunctionLibrary { returnType = annotationFields.lift(5).get.asInstanceOf[Seq[String]], inputType = annotationFields.lift(6).get.asInstanceOf[Seq[String]]) }).toSeq + } /** - * Method that will be used to call a FHIR Path function from the function library - * Function library should define the function handlers as public methods with the name of the function that gets 0 or more ExpressionContext as parameters and return Seq of FhirPathResult + * Retrieves the corresponding value of a FHIR data type from its string representation. + * This function uses reflection to access fields in the FHIR_DATA_TYPES class dynamically. + * Because the values of FHIR_DATA_TYPES that comes from ToFHIR's api usage are not accessible otherwise. + * @param fhirDataTypeString The string representation of the FHIR data type. + * @return An Option containing the string value of the FHIR data type if found, or None if not. + */ + private def getFhirDataTypeValue(fhirDataTypeString: String): Option[String] = { + // Regular expression to extract the type name from a FHIR_DATA_TYPES reference + val pattern = """.*FHIR_DATA_TYPES\.(\w+)""".r + // Match the input string against the pattern to find a corresponding FHIR type + fhirDataTypeString match { + case pattern(typeName) => + try { + // Use reflection to invoke the method corresponding to the type name + val value = FHIR_DATA_TYPES.getClass.getMethod(typeName).invoke(FHIR_DATA_TYPES) + Some(value.asInstanceOf[String]) // Return the value as an Option + } catch { + case e: Exception => + None // Return None if any exception occurs during reflection + } + case _ => + None // Return None if the input string does not match the pattern + } + } + + /** + * Parses the annotation syntax tree to extract the documentation for a FHIR path function. + * This method processes the fields of the annotation to populate the details, warnings, parameters, + * return value, and examples for the function's documentation. * - * @param fname Name of the function - * @param params Supplied parameters - * @return + * @param annotationSyntaxTree The syntax tree of the annotation from which the documentation is extracted. + * @return An instance of FhirPathFunctionDocumentation populated with the extracted fields. */ - @throws[FhirPathException] - def callFhirPathFunction(fname:String, params:Seq[ExpressionContext]):Seq[FhirPathResult] = { - try { - val method = getClass.getMethod(fname, params.map(_ => classOf[ExpressionContext]): _*) - val result = method.invoke(this, params:_*) - val fhirPathResult = result.asInstanceOf[Seq[FhirPathResult]] - fhirPathResult - } catch { - case n:NoSuchMethodException => - throw new FhirPathException(s"Invalid FHIR Path function call, function $fname does not exist or take ${params.length} arguments !!!") - case ite:InvocationTargetException => - ite.getTargetException match { - case fpe:FhirPathException => throw fpe - case e:Throwable => throw FhirPathException.apply(s"Invalid FHIR Path function call $fname!", e) + def getFhirPathDocumentation(annotationSyntaxTree: Tree): FhirPathFunctionDocumentation = { + // Initializing variables to store extracted information + var detail: String = "" + var warnings: Option[Seq[String]] = None + var parameters: Option[Seq[FhirPathFunctionParameter]] = None + var returnValue: FhirPathFunctionReturn = FhirPathFunctionReturn(None, Seq()) + var examples: Seq[String] = Seq() + + annotationSyntaxTree match { + case Apply(_: Tree, args: List[Tree]) => + // Extract the 'detail' field + args.lift(0).foreach { + case Literal(Constant(s: String)) => detail = s + } + + // Extract the 'warnings' field + args.lift(1).foreach { + case Apply(_, warningsArgs: List[Tree]) => + val extractedWarnings = warningsArgs.head.collect { + case Literal(Constant(warning: String)) => warning + } + warnings = if (extractedWarnings.nonEmpty) Some(extractedWarnings) else None + case _ => // Do nothing + } + + // Extract the 'parameters' field + args.lift(2).foreach { + case Apply(_: Tree, parametersArgs: List[Tree]) => + parametersArgs.foreach({ + case Apply(_: Tree, args: List[Tree]) => + parameters = readFhirPathFunctionParameter(args) + case _ => // Do nothing + }) + case _ => // Do nothing + } + + // Extract the 'returnValue' field + args.lift(3).foreach { + case Apply(_: Tree, returnValueArgs: List[Tree]) => + returnValue = readFhirPathFunctionReturn(returnValueArgs) + case _ => // Do nothing + } + + // Extract 'examples' field + args.lift(4).foreach { + case Apply(_: Tree, examplesArgs: List[Tree]) => + examples = examplesArgs.collect { + case Literal(Constant(example: String)) => example + } + } + + case _ => // Do nothing + } + + // Return the populated FhirPathFunctionDocumentation object + FhirPathFunctionDocumentation( + detail = detail, + usageWarnings = warnings, + parameters = parameters, + returnValue = returnValue, + examples = examples + ) + } + + /** + * Parses a list of trees to extract parameters for a FHIR path function. + * This method processes each field in the list, extracting the name, detail, and examples for each parameter. + * + * @param parameterSyntaxTreeList A list of trees representing the fields of the parameter annotation. + * @return An `Option` containing a sequence of `FhirPathFunctionParameter` objects if parameters are found, + * otherwise `None`. + */ + private def readFhirPathFunctionParameter(parameterSyntaxTreeList: List[Tree]): Option[Seq[FhirPathFunctionParameter]] = { + // Process each field in the list + val parameters = parameterSyntaxTreeList.collect { + case Apply(_: Tree, args: List[Tree]) => + // Extract values from `args` + val name = args.headOption.collect { + case Literal(Constant(value: String)) => value + }.getOrElse("") + + val detail = args.lift(1).collect { + case Literal(Constant(value: String)) => value + }.getOrElse("") + + val examples = args.lift(2) match { + case Some(Apply(_: Tree, exampleArgs: List[Tree])) => + exampleArgs.collect { + case Literal(Constant(value: String)) => value + } + case _ => Seq.empty + } + + // Construct the parameter object + FhirPathFunctionParameter(name, detail, if (examples.nonEmpty) Some(examples) else None) + } + + // Return the collected parameters wrapped in an Option + if (parameters.nonEmpty) Some(parameters) else None + } + + /** + * Extracts the return value details for a FHIR path function from a list of trees. + * This method processes the list of fields, extracting the `detail` and `examples` for the return value. + * If no valid details are found, it defaults to an empty return value. + * + * @param returnValueSyntaxTreeList A list of trees representing the fields of the return annotation. + * @return An instance of `FhirPathFunctionReturn` containing the extracted `detail` and `examples`. + */ + private def readFhirPathFunctionReturn(returnValueSyntaxTreeList: List[Tree]): FhirPathFunctionReturn = { + // Extract the `detail` and `examples` + val detail = returnValueSyntaxTreeList.headOption match { + case Some(Literal(Constant(detail: String))) => Some(detail) + case _ => None + } + + val examples = returnValueSyntaxTreeList.lift(1) match { + case Some(Apply(_: Tree, exampleArgs: List[Tree])) => + exampleArgs.collect { + case Literal(Constant(example: String)) => example } + case _ => Seq.empty } + + FhirPathFunctionReturn(detail, examples) } } diff --git a/onfhir-path/src/main/scala/io/onfhir/path/FhirPathAggFunctions.scala b/onfhir-path/src/main/scala/io/onfhir/path/FhirPathAggFunctions.scala index f39970a5..33e2365c 100644 --- a/onfhir-path/src/main/scala/io/onfhir/path/FhirPathAggFunctions.scala +++ b/onfhir-path/src/main/scala/io/onfhir/path/FhirPathAggFunctions.scala @@ -1,6 +1,7 @@ package io.onfhir.path -import io.onfhir.path.annotation.FhirPathFunction +import io.onfhir.api.FHIR_DATA_TYPES +import io.onfhir.path.annotation.{FhirPathFunction, FhirPathFunctionDocumentation, FhirPathFunctionParameter, FhirPathFunctionReturn} import io.onfhir.path.grammar.FhirPathExprParser.ExpressionContext import org.json4s.JsonAST.JObject @@ -15,8 +16,28 @@ class FhirPathAggFunctions(context:FhirPathEnvironment, current:Seq[FhirPathResu * Sum of the input numeric values, 0 if input list is empty * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the sum of the input numeric values. If the input list is empty, returns 0.\n\n\uD83D\uDD19 _@return_ \n```\n9, 9.5, etc.\n``` \n\n\uD83D\uDCA1 **E.g.** valueQuantity.value.agg:sum()", - insertText = "agg:sum()",detail = "agg", label = "agg:sum", kind = "Method", returnType = Seq("number"), inputType = Seq("number")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Returns the sum of the input numeric values. If the input list is empty, returns 0.", + usageWarnings = None, + parameters = None, + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "9, 9.5, etc." + ) + ), + examples = Seq( + "valueQuantity.value.agg:sum()" + ) + ), + insertText = "agg:sum()", + detail = "agg", + label = "agg:sum", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.DECIMAL), + inputType = Seq(FHIR_DATA_TYPES.DECIMAL) + ) def sum():Seq[FhirPathResult] = { if(current.exists(!_.isInstanceOf[FhirPathNumber])) throw new FhirPathException(s"Invalid function call 'sum', one of the input values is not a numeric value!") @@ -37,8 +58,34 @@ class FhirPathAggFunctions(context:FhirPathEnvironment, current:Seq[FhirPathResu * @param expr Expression to calculate the sum * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the sum of the numeric values in the given expression.\n\n\uD83D\uDCDD _@param_ **`expr`** \nThe expression of which the sum will be calculated.\n\n\uD83D\uDD19 _@return_ \n```\n9, 9.5, etc.\n``` \n\n\uD83D\uDCA1 **E.g.** agg:sum(valueQuantity.value)", - insertText = "agg:sum()",detail = "agg", label = "agg:sum", kind = "Function", returnType = Seq("number"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Returns the sum of the numeric values in the given expression.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "expr", + detail = "The expression of which the sum will be calculated.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "9, 9.5, etc." + ) + ), + examples = Seq( + "agg:sum(valueQuantity.value)" + ) + ), + insertText = "agg:sum()", + detail = "agg", + label = "agg:sum", + kind = "Function", + returnType = Seq(FHIR_DATA_TYPES.DECIMAL), + inputType = Seq() + ) def sum(expr:ExpressionContext):Seq[FhirPathResult] = { val results = current.map(c => { val result = new FhirPathExpressionEvaluator(context, Seq(c)).visit(expr) @@ -58,8 +105,34 @@ class FhirPathAggFunctions(context:FhirPathEnvironment, current:Seq[FhirPathResu * @param expr Expression to compute the average * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the average of the numeric values in the given expression.\n\n\uD83D\uDCDD _@param_ **`expr`** \nThe expression of which the average will be calculated.\n\n\uD83D\uDD19 _@return_ \n```\n5, 5.5, etc.\n``` \n\n\uD83D\uDCA1 **E.g.** agg:avg($this.valueQuantity.value)", - insertText = "agg:avg()",detail = "agg", label = "agg:avg", kind = "Function", returnType = Seq("number"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Returns the average of the numeric values in the given expression.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "expr", + detail = "The expression of which the average will be calculated.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "5, 5.5, etc." + ) + ), + examples = Seq( + "agg:avg($this.valueQuantity.value)" + ) + ), + insertText = "agg:avg()", + detail = "agg", + label = "agg:avg", + kind = "Function", + returnType = Seq(FHIR_DATA_TYPES.DECIMAL), + inputType = Seq() + ) def avg(expr:ExpressionContext):Seq[FhirPathResult] = { if(current.isEmpty) Nil @@ -71,8 +144,28 @@ class FhirPathAggFunctions(context:FhirPathEnvironment, current:Seq[FhirPathResu * Average of the input numeric values * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the average of the input numeric values.\n\n\uD83D\uDD19 _@return_ \n```\n5, 5.5, etc.\n``` \n\n\uD83D\uDCA1 **E.g.** valueQuantity.value.agg:avg()", - insertText = "agg:avg()",detail = "agg", label = "agg:avg", kind = "Method", returnType = Seq("number"), inputType = Seq("number")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Returns the average of the input numeric values.", + usageWarnings = None, + parameters = None, + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "5, 5.5, etc." + ) + ), + examples = Seq( + "valueQuantity.value.agg:avg()" + ) + ), + insertText = "agg:avg()", + detail = "agg", + label = "agg:avg", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.DECIMAL), + inputType = Seq(FHIR_DATA_TYPES.DECIMAL) + ) def avg():Seq[FhirPathResult] = { if(current.exists(!_.isInstanceOf[FhirPathNumber])) throw new FhirPathException(s"Invalid function call 'avg' on non numeric content!") @@ -88,8 +181,28 @@ class FhirPathAggFunctions(context:FhirPathEnvironment, current:Seq[FhirPathResu * Get the minimum of the input comparable values (numeric, dateTime * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the minimum of the input comparable values.\n\n\uD83D\uDD19 _@return_ \n```\n1, 1.5, etc.\n``` \n\n\uD83D\uDCA1 **E.g.** valueQuantity.value.agg:min()", - insertText = "agg:min()",detail = "agg", label = "agg:min", kind = "Method", returnType = Seq("string","number","dateTime","time","quantity"), inputType = Seq("string","number","dateTime","time","quantity")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Returns the minimum of the input comparable values.", + usageWarnings = None, + parameters = None, + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "1, 1.5, etc." + ) + ), + examples = Seq( + "valueQuantity.value.agg:min()" + ) + ), + insertText = "agg:min()", + detail = "agg", + label = "agg:min", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.STRING, FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.DATETIME, FHIR_DATA_TYPES.TIME, FHIR_DATA_TYPES.QUANTITY), + inputType = Seq(FHIR_DATA_TYPES.STRING, FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.DATETIME, FHIR_DATA_TYPES.TIME, FHIR_DATA_TYPES.QUANTITY) + ) def min():Seq[FhirPathResult] = { if(current.exists(c => c.isInstanceOf[FhirPathComplex] || c.isInstanceOf[FhirPathBoolean])) throw new FhirPathException(s"Invalid function call 'min' on non comparable values!") @@ -110,8 +223,34 @@ class FhirPathAggFunctions(context:FhirPathEnvironment, current:Seq[FhirPathResu * @param expr Expression to calculate * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the minimum of the comparable values in the given expression.\n\n\uD83D\uDCDD _@param_ **`expr`** \nThe expression of which the minimum will be found.\n\n\uD83D\uDD19 _@return_ \n```\n1, 1.5, etc.\n``` \n\n\uD83D\uDCA1 **E.g.** agg:min($this.valueQuantity.value)", - insertText = "agg:min()",detail = "agg", label = "agg:min", kind = "Function", returnType = Seq("string","number","dateTime","time","quantity"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Returns the minimum of the comparable values in the given expression.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "expr", + detail = "The expression of which the minimum will be found.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "1, 1.5, etc." + ) + ), + examples = Seq( + "agg:min($this.valueQuantity.value)" + ) + ), + insertText = "agg:min()", + detail = "agg", + label = "agg:min", + kind = "Function", + returnType = Seq(FHIR_DATA_TYPES.STRING, FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.DATETIME, FHIR_DATA_TYPES.TIME, FHIR_DATA_TYPES.QUANTITY), + inputType = Seq() + ) def min(expr:ExpressionContext):Seq[FhirPathResult] = { val results = current @@ -135,8 +274,34 @@ class FhirPathAggFunctions(context:FhirPathEnvironment, current:Seq[FhirPathResu * @param expr Expression to calculate * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the maximum of the comparable values in the given expression.\n\n\uD83D\uDCDD _@param_ **`expr`** \nThe expression of which the maximum will be found.\n\n\uD83D\uDD19 _@return_ \n```\n8, 8.5, etc.\n``` \n\n\uD83D\uDCA1 **E.g.** agg:max($this.valueQuantity.value)", - insertText = "agg:max()",detail = "agg", label = "agg:max", kind = "Function", returnType = Seq("string","number","dateTime","time","quantity"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Returns the maximum of the comparable values in the given expression.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "expr", + detail = "The expression of which the maximum will be found.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "8, 8.5, etc." + ) + ), + examples = Seq( + "agg:max($this.valueQuantity.value)" + ) + ), + insertText = "agg:max()", + detail = "agg", + label = "agg:max", + kind = "Function", + returnType = Seq(FHIR_DATA_TYPES.STRING, FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.DATETIME, FHIR_DATA_TYPES.TIME, FHIR_DATA_TYPES.QUANTITY), + inputType = Seq() + ) def max(expr:ExpressionContext):Seq[FhirPathResult] = { val results = current .flatMap(c => { @@ -158,8 +323,28 @@ class FhirPathAggFunctions(context:FhirPathEnvironment, current:Seq[FhirPathResu * Getting the maximum of given input values * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the maximum of the input comparable values.\n\n\uD83D\uDD19 _@return_ \n```\n8, 8.5, etc.\n``` \n\n\uD83D\uDCA1 **E.g.** valueQuantity.value.agg:max()", - insertText = "agg:max()",detail = "agg", label = "agg:max", kind = "Method", returnType = Seq("string","number","dateTime","time","quantity"), inputType = Seq("string","number","dateTime","time","quantity")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Returns the maximum of the input comparable values.", + usageWarnings = None, + parameters = None, + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "8, 8.5, etc." + ) + ), + examples = Seq( + "valueQuantity.value.agg:max()" + ) + ), + insertText = "agg:max()", + detail = "agg", + label = "agg:max", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.STRING, FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.DATETIME, FHIR_DATA_TYPES.TIME, FHIR_DATA_TYPES.QUANTITY), + inputType = Seq(FHIR_DATA_TYPES.STRING, FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.DATETIME, FHIR_DATA_TYPES.TIME, FHIR_DATA_TYPES.QUANTITY) + ) def max():Seq[FhirPathResult] = { if(current.exists(c => c.isInstanceOf[FhirPathComplex] || c.isInstanceOf[FhirPathBoolean])) throw new FhirPathException(s"Invalid function call 'max' on non comparable values!") @@ -180,8 +365,39 @@ class FhirPathAggFunctions(context:FhirPathEnvironment, current:Seq[FhirPathResu * @param aggregateExpr Aggregation expression * @return A list of special JSON Objects with field 'bucket' indicating the key for the bucket and 'agg' indicating the resulting aggregated value */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Groups the values based on some expression returning a key and applies the aggregation expression to each of these groups.\n\n\uD83D\uDCDD _@param_ **`groupByExpr`** \nAn expression to determine the key for grouping.\n\n\uD83D\uDCDD _@param_ **`aggregateExpr`** \nThe aggregation expression to apply to each group.\n\n\uD83D\uDD19 _@return_ \n```json\n[\n {\n \"bucket\": \"123\",\n \"agg\": \"2\"\n },\n {\n \"bucket\": \"456\",\n \"agg\": \"3\"\n },\n {\n \"bucket\": \"789\",\n \"agg\": \"1\"\n }\n]\n``` \n\uD83D\uDCA1 **E.g.** agg:groupBy(Condition.subject.reference.substring(8),count())", - insertText = "agg:groupBy(,)",detail = "agg", label = "agg:groupBy", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Groups the values based on some expression returning a key and applies the aggregation expression to each of these groups.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "groupByExpr", + detail = "An expression to determine the key for grouping.", + examples = None + ), + FhirPathFunctionParameter( + name = "aggregateExpr", + detail = "The aggregation expression to apply to each group.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + """[{"bucket": "123","agg": "2"},{"bucket": "456","agg": "3"},{"bucket": "789","agg": "1"}]""" + ) + ), + examples = Seq( + "agg:groupBy(Condition.subject.reference.substring(8), count())" + ) + ), + insertText = "agg:groupBy(, )", + detail = "agg", + label = "agg:groupBy", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def groupBy(groupByExpr:ExpressionContext, aggregateExpr:ExpressionContext):Seq[FhirPathResult] = { if(!current.forall(_.isInstanceOf[FhirPathComplex])) throw new FhirPathException("Invalid function call 'groupBy' on current value! The data type for current value should be complex object!") diff --git a/onfhir-path/src/main/scala/io/onfhir/path/FhirPathFunctionEvaluator.scala b/onfhir-path/src/main/scala/io/onfhir/path/FhirPathFunctionEvaluator.scala index 424b4c21..99d99ac1 100644 --- a/onfhir-path/src/main/scala/io/onfhir/path/FhirPathFunctionEvaluator.scala +++ b/onfhir-path/src/main/scala/io/onfhir/path/FhirPathFunctionEvaluator.scala @@ -1,8 +1,9 @@ package io.onfhir.path +import io.onfhir.api.FHIR_DATA_TYPES import io.onfhir.api.model.FhirLiteralReference import io.onfhir.api.util.FHIRUtil -import io.onfhir.path.annotation.FhirPathFunction +import io.onfhir.path.annotation.{FhirPathFunction, FhirPathFunctionDocumentation, FhirPathFunctionParameter, FhirPathFunctionReturn} import io.onfhir.path.grammar.FhirPathExprParser.ExpressionContext import org.apache.commons.text.StringEscapeUtils import org.json4s.JsonAST._ @@ -31,8 +32,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * @param params Supplied parameters * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Calls the specified function with parameters.\n\n\uD83D\uDCDD _@param_ **`fprefix`** \nFunction library prefix if external library (not an original FHIR Path function).\n\n\uD83D\uDCDD _@param_ **`fname`** \nFunction name.\n\n\uD83D\uDCDD _@param_ **`params`** \nSupplied parameters.\n\n\uD83D\uDD19 _@return_\n```json\n{\n \"resourceType\": \"Patient\",\n \"id\": \"12345\"\n}\n``` \n\uD83D\uDCA1 **E.g.** callFunction(None, \"resolveIdentifier\", Seq(FhirPathString(\"Patient\"), FhirPathString(\"12345\")))", - insertText = "callFunction(,,)", detail = "", label = "callFunction", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Calls the specified function with parameters.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "fprefix", detail = "Function library prefix if external library (not an original FHIR Path function).", examples = None), FhirPathFunctionParameter(name = "fname", detail = "Function name.", examples = None), FhirPathFunctionParameter(name = "params", detail = "Supplied parameters.", examples = None))), returnValue = FhirPathFunctionReturn(detail = Some("Returns the result of the function call."), examples = Seq("""{"resourceType": "Patient","id": "12345"}""")), examples = Seq("callFunction(None, \"resolveIdentifier\", Seq(FhirPathString(\"Patient\"), FhirPathString(\"12345\")))")), + insertText = "callFunction(, , )", detail = "", label = "callFunction", kind = "Function", returnType = Seq(), inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def callFunction(fprefix: Option[String], fname: String, params: Seq[ExpressionContext]): Seq[FhirPathResult] = { fprefix match { //It is an original FHIR Path function or calling it without specificying a prefix @@ -73,8 +76,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Resolves a reference.\n\n\uD83D\uDD19 _@return_\n```json\n{\n \"resourceType\": \"Patient\",\n \"id\": \"12345\"\n}\n``` \n\uD83D\uDCA1 **E.g.** resolve()", - insertText = "resolve()", detail = "", label = "resolve", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Resolves a reference.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""{"resourceType": "Patient","id": "12345"}""")), examples = Seq("resolve()")), + insertText = "resolve()", detail = "", label = "resolve", kind = "Method", returnType = Seq(), inputType = Seq() + ) def resolve(): Seq[FhirPathResult] = { val fhirReferences = current.map { //TODO We cannot distinguish every case if it is string, so we may come up with a new reference type that may be both and resolve can handle that @@ -97,8 +102,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * @param urlExp * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns a specific extension.\n\n\uD83D\uDCDD _@param_ **`urlExp`** \nURL expression.\n\n\uD83D\uDD19 _@return_\n```json\n{\n \"url\": \"http://example.org/fhir/StructureDefinition/extension\",\n \"valueString\": \"Example Value\"\n}\n``` \n\uD83D\uDCA1 **E.g.** extension(\"http://example.org/fhir/StructureDefinition/extension\")", - insertText = "extension()", detail = "", label = "extension", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns a specific extension.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "urlExp", detail = "URL expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""{"url": "http://example.org/fhir/StructureDefinition/extension", "valueString": "Example Value"}""")), examples = Seq("extension(\"http://example.org/fhir/StructureDefinition/extension\")")), + insertText = "extension()", detail = "", label = "extension", kind = "Method", returnType = Seq(), inputType = Seq() + ) def extension(urlExp: ExpressionContext): Seq[FhirPathResult] = { val url = new FhirPathExpressionEvaluator(context, current).visit(urlExp) if (url.length != 1 || !url.head.isInstanceOf[FhirPathString]) @@ -123,8 +130,8 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * @throws FhirPathException if `urlExp` does not return a valid URL. */ @FhirPathFunction( - documentation = "\uD83D\uDCDC Returns whether the current element is a member of a specific value set.\n\n\uD83D\uDCDD _@param_ **`urlExp`** \nThe URL of the FHIR value set to validate against.\n\n\uD83D\uDD19 _@return_ \nA boolean indicating if the code is valid within the specified value set:\n```json\ntrue | false\n```\n\n\uD83D\uDCA1 **E.g.** \n`code.memberOf(\"http://example.org/fhir/ValueSet/my-value-set\")`", - insertText = "memberOf()", detail = "", label = "memberOf", kind = "Method", returnType = Seq("boolean"), inputType = Seq("string") + documentation = FhirPathFunctionDocumentation(detail = "Returns whether the current element is a member of a specific value set.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "urlExp", detail = "The URL of the FHIR value set to validate against.", examples = None))), returnValue = FhirPathFunctionReturn(detail = Some("A boolean indicating if the code is valid within the specified value set."), examples = Seq("true or false")), examples = Seq("code.memberOf(\"http://example.org/fhir/ValueSet/my-value-set\")")), + insertText = "memberOf()", detail = "", label = "memberOf", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq(FHIR_DATA_TYPES.STRING) ) def memberOf(urlExp: ExpressionContext): Seq[FhirPathResult] = { // Evaluate the URL expression and ensure it resolves to a single valid URL string @@ -151,16 +158,22 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP /** * Type functions, for these basic casting or type checking are done before calling the function on the left expression */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns a collection that contains all items in the input collection that are of the given type or a subclass thereof.\n\n\uD83D\uDCDD _@param_ **`typ`** \nThe type.\n\n\uD83D\uDD19 _@return_\n```json\n[\n {\n \"resourceType\": \"Patient\",\n \"id\": \"12345\"\n }\n]\n``` \n\uD83D\uDCA1 **E.g.** ofType(\"Patient\")", - insertText = "ofType()", detail = "", label = "ofType", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns a collection that contains all items in the input collection that are of the given type or a subclass thereof.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "typ", detail = "The type.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""[{"resourceType": "Patient", "id": "12345"}]""")), examples = Seq("ofType(\"Patient\")")), + insertText = "ofType()", detail = "", label = "ofType", kind = "Method", returnType = Seq(), inputType = Seq() + ) def ofType(typ: ExpressionContext): Seq[FhirPathResult] = current - @FhirPathFunction(documentation = "\uD83D\uDCDC If the left operand is a collection with a single item and the second operand is an identifier, this operator returns the value of the left operand if it is of the type specified in the second operand, or a subclass thereof.\n\n\uD83D\uDCDD _@param_ **`typ`** \nThe type.\n\n\uD83D\uDD19 _@return_\n```json\n{\n \"resourceType\": \"Patient\",\n \"id\": \"12345\"\n}\n``` \n\uD83D\uDCA1 **E.g.** as(\"Patient\")", - insertText = "as()", detail = "", label = "as", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "If the left operand is a collection with a single item and the second operand is an identifier, this operator returns the value of the left operand if it is of the type specified in the second operand, or a subclass thereof.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "typ", detail = "The type.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""{"resourceType": "Patient", "id": "12345"}""")), examples = Seq("as(\"Patient\")")), + insertText = "as()", detail = "", label = "as", kind = "Method", returnType = Seq(), inputType = Seq() + ) def as(typ: ExpressionContext): Seq[FhirPathResult] = current - @FhirPathFunction(documentation = "\uD83D\uDCDC If the left operand is a collection with a single item and the second operand is a type identifier, this operator returns true if the type of the left operand is the type specified in the second operand, or a subclass thereof.\n\n\uD83D\uDCDD _@param_ **`typ`** \nThe type.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** is(\"Patient\")", - insertText = "is()", detail = "", label = "is", kind = "Method", returnType = Seq("boolean"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "If the left operand is a collection with a single item and the second operand is a type identifier, this operator returns true if the type of the left operand is the type specified in the second operand, or a subclass thereof.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "typ", detail = "The type.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""true or false""")), examples = Seq("is(\"Patient\")")), + insertText = "is()", detail = "", label = "is", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq() + ) def is(typ: ExpressionContext): Seq[FhirPathResult] = { current.length match { case 0 => Seq(FhirPathBoolean(false)) @@ -175,12 +188,16 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns true if the input collection is empty ({ }) and false otherwise.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** empty()", - insertText = "empty()", detail = "", label = "empty", kind = "Method", returnType = Seq("boolean"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns true if the input collection is empty ({ }) and false otherwise.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = Some("Returns true if the collection is empty, otherwise false."), examples = Seq("""true | false""")), examples = Seq("empty()")), + insertText = "empty()", detail = "", label = "empty", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq() + ) def empty(): Seq[FhirPathResult] = Seq(FhirPathBoolean(current.isEmpty)) - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns true if the input collection evaluates to false, and false if it evaluates to true.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** not()", - insertText = "not()", detail = "", label = "not", kind = "Method", returnType = Seq("boolean"), inputType = Seq("boolean")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns true if the input collection evaluates to false, and false if it evaluates to true.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("not()")), + insertText = "not()", detail = "", label = "not", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq(FHIR_DATA_TYPES.BOOLEAN) + ) def not(): Seq[FhirPathResult] = current match { case Nil => Nil case Seq(FhirPathBoolean(b)) => Seq(FhirPathBoolean(!b)) @@ -203,16 +220,22 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP Seq(FhirPathBoolean(result)) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns `true` if the collection has any elements satisfying the criteria, and `false` otherwise. For more information, refer to the [FHIRPath documentation](https://hl7.org/fhirpath/#existscriteria-expression-boolean).\n\n\uD83D\uDCDD _@param_ **`criteria`** \nThe condition or expression used to test elements within the collection. This can be any valid expression that evaluates to a boolean value (`true` or `false`).\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** identifier.exists(use = 'official')", - insertText = "exists()", detail = "", label = "exists", kind = "Method", returnType = Seq("boolean"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns `true` if the collection has any elements satisfying the criteria, and `false` otherwise. For more information, refer to the [FHIRPath documentation](https://hl7.org/fhirpath/#existscriteria-expression-boolean).", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "criteria", detail = "The condition or expression used to test elements within the collection. This can be any valid expression that evaluates to a boolean value.", examples = Some(Seq("true or false"))))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("identifier.exists(use = 'official')")), + insertText = "exists()", detail = "", label = "exists", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq() + ) def exists(expr: ExpressionContext): Seq[FhirPathResult] = exists(Some(expr)) - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns `true` if the collection has any elements, and `false` otherwise. For more information, refer to the [FHIRPath documentation](https://hl7.org/fhirpath/#existscriteria-expression-boolean).\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** name.exists()", - insertText = "exists()", detail = "", label = "exists", kind = "Method", returnType = Seq("boolean"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns `true` if the collection has any elements, and `false` otherwise. For more information, refer to the [FHIRPath documentation](https://hl7.org/fhirpath/#existscriteria-expression-boolean).", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("name.exists()")), + insertText = "exists()", detail = "", label = "exists", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq() + ) def exists(): Seq[FhirPathResult] = exists(None) - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns true if for every element in the input collection, criteria evaluates to true.\n\n\uD83D\uDCDD _@param_ **`criteria`** \nThe condition or expression used to test elements within the collection. This can be any valid expression that evaluates to a boolean value (`true` or `false`).\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** all(identifier.use = 'official')", - insertText = "all()", detail = "", label = "all", kind = "Method", returnType = Seq("boolean"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns true if for every element in the input collection, criteria evaluates to true.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "criteria", detail = "The condition or expression used to test elements within the collection. This can be any valid expression that evaluates to a boolean value.", examples = Some(Seq("true or false"))))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("all(identifier.use = 'official')")), + insertText = "all()", detail = "", label = "all", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq() + ) def all(criteria: ExpressionContext): Seq[FhirPathResult] = { val result = current @@ -226,8 +249,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP Seq(FhirPathBoolean(result)) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Takes a collection of Boolean values and returns true if all the items are true.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** allTrue()", - insertText = "allTrue()", detail = "", label = "allTrue", kind = "Method", returnType = Seq("boolean"), inputType = Seq("boolean")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Takes a collection of Boolean values and returns true if all the items are true.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("allTrue()")), + insertText = "allTrue()", detail = "", label = "allTrue", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq(FHIR_DATA_TYPES.BOOLEAN) + ) def allTrue(): Seq[FhirPathResult] = { if (current.exists(!_.isInstanceOf[FhirPathBoolean])) throw new FhirPathException("Function 'allTrue' should run on collection of FHIR Path boolean values!!!") @@ -235,8 +260,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP Seq(FhirPathBoolean(result)) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Takes a collection of Boolean values and returns true if any of the items is true.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** anyTrue()", - insertText = "anyTrue()", detail = "", label = "anyTrue", kind = "Method", returnType = Seq("boolean"), inputType = Seq("boolean")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Takes a collection of Boolean values and returns true if any of the items is true.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("anyTrue()")), + insertText = "anyTrue()", detail = "", label = "anyTrue", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq(FHIR_DATA_TYPES.BOOLEAN) + ) def anyTrue(): Seq[FhirPathResult] = { if (current.exists(!_.isInstanceOf[FhirPathBoolean])) throw new FhirPathException("Function 'anyTrue' should run on collection of FHIR Path boolean values!!!") @@ -244,8 +271,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP Seq(FhirPathBoolean(result)) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Takes a collection of Boolean values and returns true if all the items are false.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** allFalse()", - insertText = "allFalse()", detail = "", label = "allFalse", kind = "Method", returnType = Seq("boolean"), inputType = Seq("boolean")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Takes a collection of Boolean values and returns true if all the items are false.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("allFalse()")), + insertText = "allFalse()", detail = "", label = "allFalse", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq(FHIR_DATA_TYPES.BOOLEAN) + ) def allFalse(): Seq[FhirPathResult] = { if (current.exists(!_.isInstanceOf[FhirPathBoolean])) throw new FhirPathException("Function 'allFalse' should run on collection of FHIR Path boolean values!!!") @@ -253,8 +282,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP Seq(FhirPathBoolean(result)) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Takes a collection of Boolean values and returns true if any of the items is false.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** anyFalse()", - insertText = "anyFalse()", detail = "", label = "anyFalse", kind = "Method", returnType = Seq("boolean"), inputType = Seq("boolean")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Takes a collection of Boolean values and returns true if any of the items is false.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("anyFalse()")), + insertText = "anyFalse()", detail = "", label = "anyFalse", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq(FHIR_DATA_TYPES.BOOLEAN) + ) def anyFalse(): Seq[FhirPathResult] = { if (current.exists(!_.isInstanceOf[FhirPathBoolean])) throw new FhirPathException("Function 'anyFalse' should run on collection of FHIR Path boolean values!!!") @@ -262,16 +293,20 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP Seq(FhirPathBoolean(result)) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns true if all items in the input collection are members of the collection passed as the other argument.\n\n\uD83D\uDCDD _@param_ **`other`** \nThe other collection.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** subsetOf(Seq(FhirPathString(\"Patient/12345\")))", - insertText = "subsetOf()", detail = "", label = "subsetOf", kind = "Method", returnType = Seq("boolean"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns true if all items in the input collection are members of the collection passed as the other argument.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "other", detail = "The other collection.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("subsetOf(Seq(FhirPathString(\"Patient/12345\")))")), + insertText = "subsetOf()", detail = "", label = "subsetOf", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq() + ) def subsetOf(other: ExpressionContext): Seq[FhirPathResult] = { val otherCollection = new FhirPathExpressionEvaluator(context, current).visit(other) val result = current.forall(c => otherCollection.exists(o => c.isEqual(o).getOrElse(false))) Seq(FhirPathBoolean(result)) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns true if all items in the collection passed as the other argument are members of the input collection.\n\n\uD83D\uDCDD _@param_ **`other`** \nThe other collection.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** supersetOf(Seq(FhirPathString(\"Patient/12345\")))", - insertText = "supersetOf()", detail = "", label = "supersetOf", kind = "Method", returnType = Seq("boolean"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns true if all items in the collection passed as the other argument are members of the input collection.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "other", detail = "The other collection.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("supersetOf(Seq(FhirPathString(\"Patient/12345\")))")), + insertText = "supersetOf()", detail = "", label = "supersetOf", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq() + ) def supersetOf(other: ExpressionContext): Seq[FhirPathResult] = { val otherCollection = new FhirPathExpressionEvaluator(context, current).visit(other) val result = @@ -282,20 +317,27 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP Seq(FhirPathBoolean(result)) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns true if all the items in the input collection are distinct.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** isDistinct()", - insertText = "isDistinct()", detail = "", label = "isDistinct", kind = "Method", returnType = Seq("boolean"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns true if all the items in the input collection are distinct.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("isDistinct()")), + insertText = "isDistinct()", detail = "", label = "isDistinct", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq() + ) def isDistinct(): Seq[FhirPathResult] = { Seq(FhirPathBoolean(current.distinct.length == current.length)) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns a collection containing only the unique items in the input collection.\n\n\uD83D\uDD19 _@return_\n```json\n[\n {\n \"resourceType\": \"Patient\",\n \"id\": \"12345\"\n }\n]\n``` \n\uD83D\uDCA1 **E.g.** distinct()", - insertText = "distinct()", detail = "", label = "distinct", kind = "Method", returnType = Seq("boolean"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns a collection containing only the unique items in the input collection.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""[{"resourceType": "Patient","id": "12345"}]""")), examples = Seq("distinct()")), + insertText = "distinct()", detail = "", label = "distinct", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq() + ) def distinct(): Seq[FhirPathResult] = { current.distinct } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the integer count of the number of items in the input collection.\n\n\uD83D\uDD19 _@return_\n```\n3, 5, etc.\n``` \n\uD83D\uDCA1 **E.g.** count()", - insertText = "count()", detail = "", label = "count", kind = "Method", returnType = Seq("integer"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Returns the integer count of the number of items in the input collection.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("3, 5, etc.")), examples = Seq("count()")), + insertText = "count()", detail = "", label = "count", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.INTEGER), inputType = Seq() + ) def count(): Seq[FhirPathResult] = { Seq(FhirPathNumber(current.length)) } @@ -303,8 +345,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP /** * Filtering and projection http://hl7.org/fhirpath/#filtering-and-projection */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns a collection containing only those elements in the input collection for which the stated criteria expression evaluates to true.\n\n\uD83D\uDCDD _@param_ **`criteria`** \nThe condition or expression used to test elements within the collection. This can be any valid expression that evaluates to a boolean value (`true` or `false`).\n\n\uD83D\uDD19 _@return_\n```json\n[\n {\n \"resourceType\": \"Patient\",\n \"id\": \"12345\"\n }\n]\n``` \n\uD83D\uDCA1 **E.g.** where(identifier.use = 'official')", - insertText = "where()", detail = "", label = "where", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns a collection containing only those elements in the input collection for which the stated criteria expression evaluates to true.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "criteria", detail = "The condition or expression used to test elements within the collection. This can be any valid expression that evaluates to a boolean value.", examples = Some(Seq("true or false"))))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""[{"resourceType": "Patient", "id": "12345"}]""")), examples = Seq("where(identifier.use = 'official')")), + insertText = "where()", detail = "", label = "where", kind = "Method", returnType = Seq(), inputType = Seq() + ) def where(criteria: ExpressionContext): Seq[FhirPathResult] = { current .zipWithIndex @@ -319,8 +363,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP .map(_._1) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Evaluates the projection expression for each item in the input collection.\n\n\uD83D\uDCDD _@param_ **`projection`** \nThe projection expression.\n\n\uD83D\uDD19 _@return_\n```\n[\"Smith\", \"Kaplan\"]\n``` \n\uD83D\uDCA1 **E.g.** select(name.family)", - insertText = "select()", detail = "", label = "select", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Evaluates the projection expression for each item in the input collection.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "projection", detail = "The projection expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""["Smith", "Kaplan"]""")), examples = Seq("select(name.family)")), + insertText = "select()", detail = "", label = "select", kind = "Method", returnType = Seq(), inputType = Seq() + ) def select(projection: ExpressionContext): Seq[FhirPathResult] = { current .zipWithIndex @@ -330,8 +376,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP }) } - @FhirPathFunction(documentation = "\uD83D\uDCDC A version of select that will repeat the projection and add it to the output collection.\n\n\uD83D\uDCDD _@param_ **`projection`** \nThe projection expression.\n\n\uD83D\uDD19 _@return_\n```\n[\"Smith\", \"Smith\"]\n``` \n\uD83D\uDCA1 **E.g.** repeat(name.family)", - insertText = "repeat()", detail = "", label = "repeat", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "A version of select that will repeat the projection and add it to the output collection.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "projection", detail = "The projection expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""["Smith", "Smith"]""")), examples = Seq("repeat(name.family)")), + insertText = "repeat()", detail = "", label = "repeat", kind = "Method", returnType = Seq(), inputType = Seq() + ) def repeat(projection: ExpressionContext): Seq[FhirPathResult] = { val firstResults = select(projection) if (firstResults.nonEmpty) @@ -343,8 +391,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP /** * Subsetting http://hl7.org/fhirpath/#subsetting */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the single item in the input if there is just one item.\n\n\uD83D\uDD19 _@return_\n```json\n{\n \"resourceType\": \"Patient\",\n \"id\": \"12345\"\n}\n``` \n\uD83D\uDCA1 **E.g.** single()", - insertText = "single()", detail = "", label = "single", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the single item in the input if there is just one item.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""{"resourceType": "Patient", "id": "12345"}""")), examples = Seq("single()")), + insertText = "single()", detail = "", label = "single", kind = "Method", returnType = Seq(), inputType = Seq() + ) def single(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -353,20 +403,28 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP } } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns a collection containing only the first item in the input collection.\n\n\uD83D\uDD19 _@return_\n```json\n[\n {\n \"resourceType\": \"Patient\",\n \"id\": \"12345\"\n }\n]\n``` \n\uD83D\uDCA1 **E.g.** first()", - insertText = "first()", detail = "", label = "first", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns a collection containing only the first item in the input collection.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""[{"resourceType": "Patient", "id": "12345"}]""")), examples = Seq("first()")), + insertText = "first()", detail = "", label = "first", kind = "Method", returnType = Seq(), inputType = Seq() + ) def first(): Seq[FhirPathResult] = current.headOption.toSeq - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns a collection containing only the last item in the input collection. Returns an empty collection if the input collection has no items.\n\n\uD83D\uDD19 _@return_\n```json\n[\n {\n \"resourceType\": \"Patient\",\n \"id\": \"12345\"\n }\n]\n``` \n\uD83D\uDCA1 **E.g.** last()", - insertText = "last()", detail = "", label = "last", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns a collection containing only the last item in the input collection. Returns an empty collection if the input collection has no items.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""[{"resourceType": "Patient", "id": "12345"}]""")), examples = Seq("last()")), + insertText = "last()", detail = "", label = "last", kind = "Method", returnType = Seq(), inputType = Seq() + ) def last(): Seq[FhirPathResult] = current.lastOption.toSeq - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns a collection containing all but the first item in the input collection.\n\n\uD83D\uDD19 _@return_\n```json\n[\n {\n \"resourceType\": \"Patient\",\n \"id\": \"12345\"\n }\n]\n``` \n\uD83D\uDCA1 **E.g.** tail()", - insertText = "tail()", detail = "", label = "tail", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns a collection containing all but the first item in the input collection.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""[{"resourceType": "Patient", "id": "12345"}]""")), examples = Seq("tail()")), + insertText = "tail()", detail = "", label = "tail", kind = "Method", returnType = Seq(), inputType = Seq() + ) def tail(): Seq[FhirPathResult] = if (current.isEmpty) Nil else current.tail - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns a collection containing all but the first num items in the input collection.\n\n\uD83D\uDCDD _@param_ **`numExpr`** \nThe number of items to be skipped.\n\n\uD83D\uDD19 _@return_\n```json\n[\n {\n \"resourceType\": \"Patient\",\n \"id\": \"12345\"\n }\n]\n``` \n\uD83D\uDCA1 **E.g.** skip(2)", - insertText = "skip()", detail = "", label = "skip", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns a collection containing all but the first num items in the input collection.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "numExpr", detail = "The number of items to be skipped.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""[{"resourceType": "Patient", "id": "12345"}]""")), examples = Seq("skip(2)")), + insertText = "skip()", detail = "", label = "skip", kind = "Method", returnType = Seq(), inputType = Seq() + ) def skip(numExpr: ExpressionContext): Seq[FhirPathResult] = { val numValue = new FhirPathExpressionEvaluator(context, current).visit(numExpr) if (numValue.length != 1 || !numValue.head.isInstanceOf[FhirPathNumber]) @@ -384,8 +442,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP current.drop(i) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns a collection containing the first num items in the input collection, or less if there are less than num items.\n\n\uD83D\uDCDD _@param_ **`numExpr`** \nThe number of items to be included in the collection.\n\n\uD83D\uDD19 _@return_\n```json\n[\n {\n \"resourceType\": \"Patient\",\n \"id\": \"12345\"\n }\n]\n``` \n\uD83D\uDCA1 **E.g.** take(1)", - insertText = "take()", detail = "", label = "take", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns a collection containing the first num items in the input collection, or less if there are less than num items.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "numExpr", detail = "The number of items to be included in the collection.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""[{"resourceType": "Patient", "id": "12345"}]""")), examples = Seq("take(1)")), + insertText = "take()", detail = "", label = "take", kind = "Method", returnType = Seq(), inputType = Seq() + ) def take(numExpr: ExpressionContext): Seq[FhirPathResult] = { val numValue = new FhirPathExpressionEvaluator(context, current).visit(numExpr) if (numValue.length != 1 || !numValue.head.isInstanceOf[FhirPathNumber]) @@ -399,15 +459,19 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP current.take(i) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the set of elements that are in both collections.\n\n\uD83D\uDCDD _@param_ **`otherCollExpr`** \nThe other collection expression.\n\n\uD83D\uDD19 _@return_\n```json\n[\n {\n \"resourceType\": \"Patient\",\n \"id\": \"12345\"\n }\n]\n``` \n\uD83D\uDCA1 **E.g.** intersect(Seq(FhirPathString(\"Patient/12345\")))", - insertText = "intersect()", detail = "", label = "intersect", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the set of elements that are in both collections.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "otherCollExpr", detail = "The other collection expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""[{"resourceType": "Patient", "id": "12345"}]""")), examples = Seq("intersect(Seq(FhirPathString(\"Patient/12345\")))")), + insertText = "intersect()", detail = "", label = "intersect", kind = "Method", returnType = Seq(), inputType = Seq() + ) def intersect(otherCollExpr: ExpressionContext): Seq[FhirPathResult] = { val otherSet = new FhirPathExpressionEvaluator(context, current).visit(otherCollExpr) current.filter(c => otherSet.exists(o => c.isEqual(o).getOrElse(false))).distinct } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the set of elements that are not in the other collection.\n\n\uD83D\uDCDD _@param_ **`otherCollExpr`** \nThe other collection expression.\n\n\uD83D\uDD19 _@return_\n```json\n[\n {\n \"resourceType\": \"Patient\",\n \"id\": \"12345\"\n }\n]\n``` \n\uD83D\uDCA1 **E.g.** exclude(Seq(FhirPathString(\"Patient/54321\")))", - insertText = "exclude()", detail = "", label = "exclude", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the set of elements that are not in the other collection.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "otherCollExpr", detail = "The other collection expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""[{"resourceType": "Patient", "id": "12345"}]""")), examples = Seq("exclude(Seq(FhirPathString(\"Patient/54321\")))")), + insertText = "exclude()", detail = "", label = "exclude", kind = "Method", returnType = Seq(), inputType = Seq() + ) def exclude(otherCollExpr: ExpressionContext): Seq[FhirPathResult] = { val otherSet = new FhirPathExpressionEvaluator(context, current).visit(otherCollExpr) current.filterNot(c => otherSet.exists(o => c.isEqual(o).getOrElse(false))).distinct @@ -420,8 +484,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the absolute value of the input. When taking the absolute value of a quantity, the unit is unchanged. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.\n\n\uD83D\uDD19 _@return_\n```\n3, 3.5, etc.\n``` \n\uD83D\uDCA1 **E.g.** 3.abs()", - insertText = "abs()", detail = "", label = "abs", kind = "Method", returnType = Seq("number", "quantity"), inputType = Seq("number", "quantity")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the absolute value of the input. When taking the absolute value of a quantity, the unit is unchanged. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("3, 3.5, etc.")), examples = Seq("3.abs()")), + insertText = "abs()", detail = "", label = "abs", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY) + ) def abs(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -438,8 +504,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the first integer greater than or equal to the input. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.\n\n\uD83D\uDD19 _@return_\n```\n3, 5, etc.\n``` \n\uD83D\uDCA1 **E.g.** 2.5.ceiling()", - insertText = "ceiling()", detail = "", label = "ceiling", kind = "Method", returnType = Seq("number", "quantity"), inputType = Seq("number", "quantity")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the first integer greater than or equal to the input. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("3, 5, etc.")), examples = Seq("2.5.ceiling()")), + insertText = "ceiling()", detail = "", label = "ceiling", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY) + ) def ceiling(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -457,8 +525,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns e raised to the power of the input. If the input collection contains an Integer, it will be implicitly converted to a Decimal and the result will be a Decimal. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.\n\n\uD83D\uDD19 _@return_\n```\n7.38905609893065\n``` \n\uD83D\uDCA1 **E.g.** 2.exp()", - insertText = "exp()", detail = "", label = "exp", kind = "Method", returnType = Seq("number", "quantity"), inputType = Seq("number", "quantity")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns e raised to the power of the input. If the input collection contains an Integer, it will be implicitly converted to a Decimal and the result will be a Decimal. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("7.38905609893065")), examples = Seq("2.exp()")), + insertText = "exp()", detail = "", label = "exp", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY) + ) def exp(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -475,8 +545,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the first integer less than or equal to the input. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.\n\n\uD83D\uDD19 _@return_\n```\n3, 5, etc.\n``` \n\uD83D\uDCA1 **E.g.** 3.5.floor()", - insertText = "floor()", detail = "", label = "floor", kind = "Method", returnType = Seq("number", "quantity"), inputType = Seq("number", "quantity")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the first integer less than or equal to the input. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("3", "5")), examples = Seq("3.5.floor()")), + insertText = "floor()", detail = "", label = "floor", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY) + ) def floor(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -494,8 +566,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the natural logarithm of the input (i.e. the logarithm base e). When used with an Integer, it will be implicitly converted to a Decimal. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.\n\n\uD83D\uDD19 _@return_\n```\n2.302585092994046\n``` \n\uD83D\uDCA1 **E.g.** 10.ln()", - insertText = "ln()", detail = "", label = "ln", kind = "Method", returnType = Seq("number", "quantity"), inputType = Seq("number", "quantity")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the natural logarithm of the input (i.e. the logarithm base e). When used with an Integer, it will be implicitly converted to a Decimal. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("2.302585092994046")), examples = Seq("10.ln()")), + insertText = "ln()", detail = "", label = "ln", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY) + ) def ln(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -515,8 +589,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * @param baseExp * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the logarithm base \"base\" of the input number. When used with Integers, the arguments will be implicitly converted to Decimal. If base is empty, the result is empty. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.\n\n\uD83D\uDCDD _@param_ **`baseExp`** \nThe base expression.\n\n\uD83D\uDD19 _@return_\n```\n0.301029995663981\n``` \n\uD83D\uDCA1 **E.g.** 2.log(10)", - insertText = "log()", detail = "", label = "log", kind = "Method", returnType = Seq("number", "quantity"), inputType = Seq("number", "quantity")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the logarithm base \"base\" of the input number. When used with Integers, the arguments will be implicitly converted to Decimal. If base is empty, the result is empty. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "baseExp", detail = "The base expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("0.301029995663981")), examples = Seq("2.log(10)")), + insertText = "log()", detail = "", label = "log", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY) + ) def log(baseExp: ExpressionContext): Seq[FhirPathResult] = { val baseResult = new FhirPathExpressionEvaluator(context, current).visit(baseExp) if (baseResult.length != 1 || !baseResult.head.isInstanceOf[FhirPathNumber]) @@ -539,8 +615,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * @param exponentExpr * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Raises a number to the exponent power. If this function is used with Integers, the result is an Integer. If the function is used with Decimals, the result is a Decimal. If the function is used with a mixture of Integer and Decimal, the Integer is implicitly converted to a Decimal and the result is a Decimal. If the power cannot be represented (such as the -1 raised to the 0.5), the result is empty. If the input is empty, or exponent is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.\n\n\uD83D\uDCDD _@param_ **`exponentExpr`** \nThe exponent expression.\n\n\uD83D\uDD19 _@return_\n```\n8, 1.414213562373095, etc.\n``` \n\uD83D\uDCA1 **E.g.** 2.power(3), 2.power(0.5), etc.", - insertText = "power()", detail = "", label = "power", kind = "Method", returnType = Seq("number", "quantity"), inputType = Seq("number", "quantity")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Raises a number to the exponent power. If this function is used with Integers, the result is an Integer. If the function is used with Decimals, the result is a Decimal. If the function is used with a mixture of Integer and Decimal, the Integer is implicitly converted to a Decimal and the result is a Decimal. If the power cannot be represented (such as -1 raised to 0.5), the result is empty. If the input is empty, or exponent is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "exponentExpr", detail = "The exponent expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("8", "1.414213562373095")), examples = Seq("2.power(3)", "2.power(0.5)")), + insertText = "power()", detail = "", label = "power", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY) + ) def power(exponentExpr: ExpressionContext): Seq[FhirPathResult] = { val exponentResult = new FhirPathExpressionEvaluator(context, current).visit(exponentExpr) if (exponentResult.length != 1 || !exponentResult.head.isInstanceOf[FhirPathNumber]) @@ -561,8 +639,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Rounds the decimal to the nearest whole number using a traditional round (i.e. 0.5 or higher will round to 1). If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.\n\n\uD83D\uDD19 _@return_\n```\n3, 5, etc.\n``` \n\uD83D\uDCA1 **E.g.** 2.9.round()", - insertText = "round()", detail = "", label = "round", kind = "Method", returnType = Seq("number", "quantity"), inputType = Seq("number", "quantity")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Rounds the decimal to the nearest whole number using a traditional round (i.e. 0.5 or higher will round to 1). If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("3", "5")), examples = Seq("2.9.round()")), + insertText = "round()", detail = "", label = "round", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY) + ) def round(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -581,8 +661,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * @param precisionExpr * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Rounds the decimal in a way that the precision argument determines the decimal place at which the rounding will occur. The number of digits of precision must be >= 0 or the evaluation will end and signal an error to the calling environment. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.\n\n\uD83D\uDCDD _@param_ **`precisionExpr`** \nThe precision expression.\n\n\uD83D\uDD19 _@return_\n```\n3.33\n``` \n\uD83D\uDCA1 **E.g.** 3.3333.round(2)", - insertText = "round()", detail = "", label = "round", kind = "Method", returnType = Seq("number", "quantity"), inputType = Seq("number", "quantity")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Rounds the decimal in a way that the precision argument determines the decimal place at which the rounding will occur. The number of digits of precision must be >= 0 or the evaluation will end and signal an error to the calling environment. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "precisionExpr", detail = "The precision expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("3.33")), examples = Seq("3.3333.round(2)")), + insertText = "round()", detail = "", label = "round", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY) + ) def round(precisionExpr: ExpressionContext): Seq[FhirPathResult] = { val precisionResult = new FhirPathExpressionEvaluator(context, current).visit(precisionExpr) precisionResult match { @@ -607,8 +689,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the square root of the input number as a Decimal. If the square root cannot be represented (such as the square root of -1), the result is empty. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.\n\n\uD83D\uDD19 _@return_\n```\n1.414213562373095\n``` \n\uD83D\uDCA1 **E.g.** 2.sqrt()", - insertText = "sqrt()", detail = "", label = "sqrt", kind = "Method", returnType = Seq("number", "quantity"), inputType = Seq("number", "quantity")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the square root of the input number as a Decimal. If the square root cannot be represented (such as the square root of -1), the result is empty. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("1.414213562373095")), examples = Seq("2.sqrt()")), + insertText = "sqrt()", detail = "", label = "sqrt", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY) + ) def sqrt(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -635,8 +719,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the integer portion of the input. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.\n\n\uD83D\uDD19 _@return_\n```\n3, 5, etc.\n``` \n\uD83D\uDCA1 **E.g.** 3.9.truncate()", - insertText = "truncate()", detail = "", label = "truncate", kind = "Method", returnType = Seq("number", "quantity"), inputType = Seq("number", "quantity")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the integer portion of the input. If the input collection is empty, the result is empty. If the input collection contains multiple items, the evaluation of the expression will end and signal an error to the calling environment.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("3, 5, etc.")), examples = Seq("3.9.truncate()")), + insertText = "truncate()", detail = "", label = "truncate", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY) + ) def truncate(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -653,8 +739,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * @param other * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Merges the input and other collections into a single collection without eliminating duplicate values.\n\n\uD83D\uDCDD _@param_ **`other`** \nThe other collection.\n\n\uD83D\uDD19 _@return_\n```\n[\"1\", \"2\", \"3\", \"4\", \"5\"]\n``` \n\uD83D\uDCA1 **E.g.** combine(['1', '2', '3'])", - insertText = "combine()", detail = "", label = "combine", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Merges the input and other collections into a single collection without eliminating duplicate values.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "other", detail = "The other collection.", None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""["1", "2", "3", "4", "5"]""")), examples = Seq("combine(['1', '2', '3'])")), + insertText = "combine()", detail = "", label = "combine", kind = "Method", returnType = Seq(), inputType = Seq() + ) def combine(other: ExpressionContext): Seq[FhirPathResult] = { val otherCollection = new FhirPathExpressionEvaluator(context, current).visit(other) current ++ otherCollection @@ -676,12 +764,16 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP otherwiseResult.map(ore => new FhirPathExpressionEvaluator(context, current).visit(ore)).getOrElse(Nil) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Evaluates a given criterion and returns one of two specified results based on whether the criterion is true or false. It functions similarly to an inline if-else statement.\n\n\uD83D\uDCDD _@param_ **`criterium`** \nThe condition or expression to be evaluated. This can be any expression that resolves to a boolean value (`true` or `false`).\n\n\uD83D\uDCDD _@param_ **`trueResult`** \nThe value to be returned if the `criterium` evaluates to true. This can be any valid value or expression.\n\n\uD83D\uDCDD _@param_ **`otherwiseResult`** \nThe value to be returned if the `criterium` evaluates to false. This can be any valid value or expression.\n\n\uD83D\uDD19 _@return_ \nThe method returns the value of `trueResult` if `criterium` is true, otherwise it returns the value of `otherwiseResult`.\n\n\uD83D\uDCA1 **E.g.** iif(measuredLabValue >= 50, 'High', 'Normal')", - insertText = "iif(, , )", detail = "", label = "iif", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Evaluates a given criterion and returns one of two specified results based on whether the criterion is true or false. It functions similarly to an inline if-else statement.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "criterium", detail = "The condition or expression to be evaluated. This can be any expression that resolves to a boolean value.", examples = Some(Seq("true or false"))), FhirPathFunctionParameter(name = "trueResult", detail = "The value to be returned if the `criterium` evaluates to true. This can be any valid value or expression.", examples = None), FhirPathFunctionParameter(name = "otherwiseResult", detail = "The value to be returned if the `criterium` evaluates to false. This can be any valid value or expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = Some("The method returns the value of `trueResult` if `criterium` is true, otherwise it returns the value of `otherwiseResult`."), examples = Seq("'High'", "'Normal'")), examples = Seq("iif(measuredLabValue >= 50, 'High', 'Normal')")), + insertText = "iif(, , )", detail = "", label = "iif", kind = "Function", returnType = Seq(), inputType = Seq() + ) def iif(criterium: ExpressionContext, trueResult: ExpressionContext, otherwiseResult: ExpressionContext): Seq[FhirPathResult] = iif(criterium, trueResult, Some(otherwiseResult)) - @FhirPathFunction(documentation = "\uD83D\uDCDC Evaluates a given criterion and returns a specified result if the criterion is true. If the criterion is false, it returns an empty value.\n\n\uD83D\uDCDD _@param_ **`criterium`** \nThe condition or expression to be evaluated. This can be any expression that resolves to a boolean value (`true` or `false`).\n\n\uD83D\uDCDD _@param_ **`trueResult`** \nThe value to be returned if the `criterium` evaluates to true. This can be any valid value or expression.\n\n\uD83D\uDD19 _@return_ \nThe method returns the value of `trueResult` if `criterium` is true. If `criterium` is false, it returns an empty value.\n\n\uD83D\uDCA1 **E.g.** iif(measuredLabValue >= 50, 'High')", - insertText = "iif(,)", detail = "", label = "iif", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Evaluates a given criterion and returns a specified result if the criterion is true. If the criterion is false, it returns an empty value.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "criterium", detail = "The condition or expression to be evaluated. This can be any expression that resolves to a boolean value.", examples = Some(Seq("true or false"))), FhirPathFunctionParameter(name = "trueResult", detail = "The value to be returned if the `criterium` evaluates to true. This can be any valid value or expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = Some("The method returns the value of `trueResult` if `criterium` is true. If `criterium` is false, it returns an empty value."), examples = Seq("'High'")), examples = Seq("iif(measuredLabValue >= 50, 'High')")), + insertText = "iif(, )", detail = "", label = "iif", kind = "Function", returnType = Seq(), inputType = Seq() + ) def iif(criterium: ExpressionContext, trueResult: ExpressionContext): Seq[FhirPathResult] = iif(criterium, trueResult, None) @@ -690,8 +782,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Converts the input to an integer.\n\n\uD83D\uDD19 _@return_\n```\n3, 5, etc.\n``` \n\uD83D\uDCA1 **E.g.** '3'.toInteger()", - insertText = "toInteger()", detail = "", label = "toInteger", kind = "Method", returnType = Seq("integer"), inputType = Seq("integer", "string", "boolean")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Converts the input to an integer.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("3", "5")),examples = Seq("'3'.toInteger()")), + insertText = "toInteger()", detail = "", label = "toInteger", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.INTEGER), inputType = Seq(FHIR_DATA_TYPES.INTEGER, FHIR_DATA_TYPES.STRING, FHIR_DATA_TYPES.BOOLEAN) + ) def toInteger(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -712,8 +806,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Converts the input to a decimal.\n\n\uD83D\uDD19 _@return_\n```\n3.5, 5.8, etc.\n``` \n\uD83D\uDCA1 **E.g.** '3.5'.toDecimal()", - insertText = "toDecimal()", detail = "", label = "toDecimal", kind = "Method", returnType = Seq("decimal"), inputType = Seq("dateTime", "number", "string", "boolean")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Converts the input to a decimal.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = Some("The method returns the decimal representation of the input."), examples = Seq("3.5", "5.8")), examples = Seq("'3.5'.toDecimal()")), + insertText = "toDecimal()", detail = "", label = "toDecimal", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DECIMAL), inputType = Seq(FHIR_DATA_TYPES.DATETIME, FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.STRING, FHIR_DATA_TYPES.BOOLEAN) + ) def toDecimal(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -735,8 +831,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Checks if the current item can be converted to decimal. If so, returns true. Otherwise, returns false.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** '3.5'.convertsToDecimal()", - insertText = "convertsToDecimal()", detail = "", label = "convertsToDecimal", kind = "Method", returnType = Seq("boolean"), inputType = Seq("dateTime", "number", "boolean", "string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Checks if the current item can be converted to a decimal. If so, returns true. Otherwise, returns false.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("'3.5'.convertsToDecimal()")), + insertText = "convertsToDecimal()", detail = "", label = "convertsToDecimal", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq(FHIR_DATA_TYPES.DATETIME, FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.BOOLEAN, FHIR_DATA_TYPES.STRING) + ) def convertsToDecimal(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -758,8 +856,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Converts the input to a boolean.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** 'true'.toBoolean()", - insertText = "toBoolean()", detail = "", label = "toBoolean", kind = "Method", returnType = Seq("boolean"), inputType = Seq("number", "string", "boolean")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Converts the input to a boolean.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("'true'.toBoolean()")), + insertText = "toBoolean()", detail = "", label = "toBoolean", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.STRING, FHIR_DATA_TYPES.BOOLEAN) + ) def toBoolean(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -790,8 +890,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Converts the input to a Date format. This method follows the FHIRPath standard and only accepts a single format: YYYY-MM-DD. For more information, refer to the [FHIRPath documentation](https://hl7.org/fhirpath/#todate-date). \nâš \uFE0F For custom patterns and conversion purposes, please use the `utl` library methods (e.g., `utl:toFhirDate`).\n\n\uD83D\uDD19 _@return_ \nThe method returns a Date string in the format YYYY-MM-DD.\n```json\n\"2023-05-23\"\n```\n\uD83D\uDCA1 **E.g.** '2012-01-01'.toDate()", - insertText = "toDate()", detail = "", label = "toDate", kind = "Method", returnType = Seq("dateTime"), inputType = Seq("dateTime", "string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Converts the input to a Date format. This method follows the FHIRPath standard and only accepts a single format: YYYY-MM-DD. For more information, refer to the [FHIRPath documentation](https://hl7.org/fhirpath/#todate-date).", usageWarnings = Some(Seq("For custom patterns and conversion purposes, please use the `utl` library methods (e.g., `utl:toFhirDate`).")), parameters = None, returnValue = FhirPathFunctionReturn(detail = Some("The method returns a Date string in the format YYYY-MM-DD."), examples = Seq("\"2023-05-23\"")), examples = Seq("'2012-01-01'.toDate()")), + insertText = "toDate()", detail = "", label = "toDate", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DATETIME), inputType = Seq(FHIR_DATA_TYPES.DATETIME, FHIR_DATA_TYPES.STRING) + ) def toDate(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -812,8 +914,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Converts the input to a DateTime format. This method follows the FHIRPath standard and only accepts a single format: YYYY-MM-DDThh:mm:ss.fff(+|-)hh:mm. For more information, refer to the [FHIRPath documentation](https://hl7.org/fhirpath/#todatetime-datetime). \nâš \uFE0F For custom patterns and conversion purposes, please use the `utl` library methods (e.g., `utl:toFhirDateTime`).\n\n\uD83D\uDD19 _@return_ \nThe method returns a DateTime string in the format YYYY-MM-DDThh:mm:ss.fff(+|-)hh:mm.\n```json\n\"2023-05-23T13:45:30.000+02:00\"\n```\n\uD83D\uDCA1 **E.g.** '2012-01-01T10:00'.toDateTime()", - insertText = "toDateTime()", detail = "", label = "toDateTime", kind = "Method", returnType = Seq("dateTime"), inputType = Seq("dateTime", "string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Converts the input to a DateTime format. This method follows the FHIR Path standard and only accepts a single format: YYYY-MM-DDThh:mm:ss.fff(+|-)hh:mm. For more information, refer to the [FHIRPath documentation](https://hl7.org/fhirpath/#todatetime-datetime).", usageWarnings = Some(Seq("For custom patterns and conversion purposes, please use the `utl` library methods (e.g., `utl:toFhirDateTime`).")), parameters = None, returnValue = FhirPathFunctionReturn(detail = Some("The method returns a DateTime string in the format YYYY-MM-DDThh:mm:ss.fff(+|-)hh:mm."), examples = Seq("\"2023-05-23T13:45:30.000+02:00\"")), examples = Seq("'2012-01-01T10:00'.toDateTime()")), + insertText = "toDateTime()", detail = "", label = "toDateTime", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DATETIME), inputType = Seq(FHIR_DATA_TYPES.DATETIME, FHIR_DATA_TYPES.STRING) + ) def toDateTime(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -830,8 +934,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP } } - @FhirPathFunction(documentation = "\uD83D\uDCDC Converts the input to a quantity.\n\n\uD83D\uDD19 _@return_\n```json\n{\n \"value\": 3,\n \"unit\": \"1\"\n}\n``` \n\uD83D\uDCA1 **E.g.** '3'.toQuantity()", - insertText = "toQuantity()", detail = "", label = "toQuantity", kind = "Method", returnType = Seq("quantity"), inputType = Seq("number", "quantity", "string", "boolean")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Converts the input to a quantity.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""{"value": 3, "unit": 1}""")), examples = Seq("'3'.toQuantity()")), + insertText = "toQuantity()", detail = "", label = "toQuantity", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.QUANTITY), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY, FHIR_DATA_TYPES.STRING, FHIR_DATA_TYPES.BOOLEAN) + ) def toQuantity(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -846,8 +952,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP } } - @FhirPathFunction(documentation = "\uD83D\uDCDC Converts the input to a quantity with the given unit.\n\n\uD83D\uDCDD _@param_ **`unitExpr`** \nThe unit expression.\n\n\uD83D\uDD19 _@return_\n```json\n{\n \"value\": 3,\n \"unit\": \"mg\"\n}\n``` \n\uD83D\uDCA1 **E.g.** '3'.toQuantity('mg')", - insertText = "toQuantity()", detail = "", label = "toQuantity", kind = "Method", returnType = Seq("quantity"), inputType = Seq("number", "quantity", "string", "boolean")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Converts the input to a quantity with the given unit.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "unitExpr", detail = "The unit expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = Some("The method returns a quantity object with value and unit."), examples = Seq("""{"value": 3, "unit": "mg"}""")), examples = Seq("'3'.toQuantity('mg')")), + insertText = "toQuantity()", detail = "", label = "toQuantity", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.QUANTITY), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.QUANTITY, FHIR_DATA_TYPES.STRING, FHIR_DATA_TYPES.BOOLEAN) + ) def toQuantity(unitExpr: ExpressionContext): Seq[FhirPathResult] = { val unitValue = new FhirPathExpressionEvaluator(context, current).visit(unitExpr) if (!unitValue.forall(_.isInstanceOf[FhirPathString])) @@ -871,8 +979,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Converts the input to a string.\n\n\uD83D\uDD19 _@return_\n```\n\"3\"\n``` \n\uD83D\uDCA1 **E.g.** 3.toString()", - insertText = "toString()", detail = "", label = "toString", kind = "Method", returnType = Seq("string"), inputType = Seq("number", "string", "dateTime", "time", "quantity", "boolean")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Converts the input to a string.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("\"3\"")), examples = Seq("3.toString()")), + insertText = "toString()", detail = "", label = "toString", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.STRING), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.STRING, FHIR_DATA_TYPES.DATETIME, FHIR_DATA_TYPES.TIME, FHIR_DATA_TYPES.QUANTITY, FHIR_DATA_TYPES.BOOLEAN) + ) def _toString(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -888,8 +998,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP } } - @FhirPathFunction(documentation = "\uD83D\uDCDC Converts a quantity to a FHIR Path Object type (JSON).\n\n\uD83D\uDD19 _@return_\n```json\n{\n \"value\": 3,\n \"unit\": \"mg\"\n}\n``` \n\uD83D\uDCA1 **E.g.** {'value': 3, 'unit': 'mg'}.toComplex()", - insertText = "toComplex()", detail = "", label = "toComplex", kind = "Method", returnType = Seq(), inputType = Seq("quantity")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Converts a quantity to a FHIR Path Object type (JSON).", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = Some("The method returns a FHIR Path Object (JSON) representing the quantity with value and unit."), examples = Seq("""{"value": 3,"unit": "mg"}""")), examples = Seq("{'value': 3, 'unit': 'mg'}.toComplex()")), + insertText = "toComplex()", detail = "", label = "toComplex", kind = "Method", returnType = Seq(), inputType = Seq(FHIR_DATA_TYPES.QUANTITY) + ) def toComplex(): Seq[FhirPathResult] = { current match { case Seq(q: FhirPathQuantity) => Seq(FhirPathComplex(q.toJson.asInstanceOf[JObject])) @@ -907,8 +1019,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP if (current.length > 1 || current.headOption.exists(!_.isInstanceOf[FhirPathString])) throw new FhirPathException("Invalid function call on multi item collection or non-string value!") - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the 0-based index of the first position the given substring is found in the input string, or -1 if it is not found.\n\n\uD83D\uDCDD _@param_ **`substringExpr`** \nThe substring expression.\n\n\uD83D\uDD19 _@return_\n```\n1, 3, etc.\n``` \n\uD83D\uDCA1 **E.g.** 'abcdefg'.indexOf('bc')", - insertText = "indexOf()", detail = "", label = "indexOf", kind = "Method", returnType = Seq("integer"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the 0-based index of the first position the given substring is found in the input string, or -1 if it is not found.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "substringExpr", detail = "The substring expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("1", "3")), examples = Seq("'abcdefg'.indexOf('bc')")), + insertText = "indexOf()", detail = "", label = "indexOf", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.INTEGER), inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def indexOf(substringExpr: ExpressionContext): Seq[FhirPathResult] = { checkSingleString() current.headOption.map(c => { @@ -944,16 +1058,22 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP }).getOrElse(Nil) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the part of the string starting at position start (zero-based).\n\n\uD83D\uDCDD _@param_ **`startExpr`** \nThe start position expression.\n\n\uD83D\uDD19 _@return_\n```\n\"bcdefg\"\n``` \n\uD83D\uDCA1 **E.g.** 'abcdefg'.substring(1)", - insertText = "substring()", detail = "", label = "substring", kind = "Method", returnType = Seq("string"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the part of the string starting at position start (zero-based).", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "startExpr", detail = "The start position expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("\"bcdefg\"")), examples = Seq("'abcdefg'.substring(1)")), + insertText = "substring()", detail = "", label = "substring", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.STRING), inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def substring(startExpr: ExpressionContext): Seq[FhirPathResult] = substring(startExpr, None) - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the part of the string starting at position start (zero-based) and being of the given length.\n\n\uD83D\uDCDD _@param_ **`startExpr`** \nThe start position expression.\n\n\uD83D\uDCDD _@param_ **`lengthExpr`** \nThe length expression for the substring.\n\n\uD83D\uDD19 _@return_\n```\n\"bcd\"\n``` \n\uD83D\uDCA1 **E.g.** 'abcdefg'.substring(1, 3)", - insertText = "substring(,)", detail = "", label = "substring", kind = "Method", returnType = Seq("string"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the part of the string starting at position start (zero-based) and being of the given length.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "startExpr", detail = "The start position expression.", examples = None), FhirPathFunctionParameter(name = "lengthExpr", detail = "The length expression for the substring.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("\"bcd\"")), examples = Seq("'abcdefg'.substring(1, 3)")), + insertText = "substring(,)", detail = "", label = "substring", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.STRING), inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def substring(startExpr: ExpressionContext, lengthExpr: ExpressionContext): Seq[FhirPathResult] = substring(startExpr, Some(lengthExpr)) - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns true if the input string starts with the given prefix.\n\n\uD83D\uDCDD _@param_ **`prefixExpr`** \nThe prefix expression.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** 'abcdefg'.startsWith('abc')", - insertText = "startsWith()", detail = "", label = "startsWith", kind = "Method", returnType = Seq("boolean"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns true if the input string starts with the given prefix.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "prefixExpr", detail = "The prefix expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("'abcdefg'.startsWith('abc')")), + insertText = "startsWith()", detail = "", label = "startsWith", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def startsWith(prefixExpr: ExpressionContext): Seq[FhirPathResult] = { checkSingleString() current.headOption.map(c => { @@ -967,8 +1087,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP }).getOrElse(Nil) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns true if the input string ends with the given suffix.\n\n\uD83D\uDCDD _@param_ **`suffixExpr`** \nThe suffix expression.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** 'abcdefg'.endsWith('efg')", - insertText = "endsWith()", detail = "", label = "endsWith", kind = "Method", returnType = Seq("boolean"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns true if the input string ends with the given suffix.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "suffixExpr", detail = "The suffix expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("'abcdefg'.endsWith('efg')")), + insertText = "endsWith()", detail = "", label = "endsWith", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def endsWith(suffixExpr: ExpressionContext): Seq[FhirPathResult] = { checkSingleString() current.headOption.map(c => { @@ -979,8 +1101,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP }).getOrElse(Nil) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns true if the given substring is a substring of the input string.\n\n\uD83D\uDCDD _@param_ **`substringExpr`** \nThe substring expression.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** 'abcdefg'.contains('cde')", - insertText = "contains()", detail = "", label = "contains", kind = "Method", returnType = Seq("boolean"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns true if the given substring is a substring of the input string.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "substringExpr", detail = "The substring expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("'abcdefg'.contains('cde')")), + insertText = "contains()", detail = "", label = "contains", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def _contains(substringExpr: ExpressionContext): Seq[FhirPathResult] = { checkSingleString() current.headOption.map(c => { @@ -991,8 +1115,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP }).getOrElse(Nil) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the input string with all instances of the given pattern replaced with the given substitution.\n\n\uD83D\uDCDD _@param_ **`patternExpr`** \nThe pattern expression.\n\n\uD83D\uDCDD _@param_ **`substitutionExpr`** \nThe substitution expression.\n\n\uD83D\uDD19 _@return_\n```\n\"ab123fg\"\n``` \n\uD83D\uDCA1 **E.g.** 'abcdefg'.replace('cde', '123')", - insertText = "replace(,)", detail = "", label = "replace", kind = "Method", returnType = Seq("string"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the input string with all instances of the given pattern replaced with the given substitution.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "patternExpr", detail = "The pattern expression.", examples = None), FhirPathFunctionParameter(name = "substitutionExpr", detail = "The substitution expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("\"ab123fg\"")), examples = Seq("'abcdefg'.replace('cde', '123')")), + insertText = "replace(,)", detail = "", label = "replace", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.STRING), inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def replace(patternExpr: ExpressionContext, substitutionExpr: ExpressionContext): Seq[FhirPathResult] = { checkSingleString() current.headOption.map(c => { @@ -1010,8 +1136,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP }).getOrElse(Nil) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns true if the input value matches the given regular expression.\n\n\uD83D\uDCDD _@param_ **`regexExpr`** \nThe regular expression.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** 'abcdefg'.matches('a.c.e.g')", - insertText = "matches()", detail = "", label = "matches", kind = "Method", returnType = Seq("boolean"), inputType = Seq("string", "dateTime", "number")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns true if the input value matches the given regular expression.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "regexExpr", detail = "The regular expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("'abcdefg'.matches('a.c.e.g')")), + insertText = "matches()", detail = "", label = "matches", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq(FHIR_DATA_TYPES.STRING, FHIR_DATA_TYPES.DATETIME, FHIR_DATA_TYPES.DECIMAL) + ) def matches(regexExpr: ExpressionContext): Seq[FhirPathResult] = { current.headOption.map(c => { new FhirPathExpressionEvaluator(context, current).visit(regexExpr) match { @@ -1032,8 +1160,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP }).getOrElse(Nil) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Matches the input using the given regular expression and replaces each match with the given substitution string.\n\n\uD83D\uDCDD _@param_ **`regexExpr`** \nThe regular expression.\n\n\uD83D\uDCDD _@param_ **`substitutionExpr`** \nThe substitution expression.\n\n\uD83D\uDD19 _@return_\n```\n\"ab123fg\"\n``` \n\uD83D\uDCA1 **E.g.** 'abcdefg'.replaceMatches('c.e', '123')", - insertText = "replaceMatches(,)", detail = "", label = "replaceMatches", kind = "Method", returnType = Seq("string"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Matches the input using the given regular expression and replaces each match with the given substitution string.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "regexExpr", detail = "The regular expression.", examples = None), FhirPathFunctionParameter(name = "substitutionExpr", detail = "The substitution expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("\"ab123fg\"")), examples = Seq("'abcdefg'.replaceMatches('c.e', '123')")), + insertText = "replaceMatches(,)", detail = "", label = "replaceMatches", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.STRING), inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def replaceMatches(regexExpr: ExpressionContext, substitutionExpr: ExpressionContext): Seq[FhirPathResult] = { checkSingleString() current.headOption.map(c => { @@ -1051,15 +1181,19 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP }).getOrElse(Nil) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the length of the input string.\n\n\uD83D\uDD19 _@return_\n```\n5, 7, etc.\n``` \n\uD83D\uDCA1 **E.g.** 'abcdefg'.length()", - insertText = "length()", detail = "", label = "length", kind = "Method", returnType = Seq("integer"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the length of the input string.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("5", "7")), examples = Seq("'abcdefg'.length()")), + insertText = "length()", detail = "", label = "length", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.INTEGER), inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def length(): Seq[FhirPathResult] = { checkSingleString() current.headOption.map(c => Seq(FhirPathNumber(c.asInstanceOf[FhirPathString].s.length))).getOrElse(Nil) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Encodes the input string to a Base64-encoded binary.\n\n\uD83D\uDD19 _@return_\n```\nZmluYWw=\n``` \n\uD83D\uDCA1 **E.g.** 'final'.encode()", - insertText = "encode()", detail = "", label = "encode", kind = "Method", returnType = Seq("base64Binary"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Encodes the input string to a Base64-encoded binary.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("\"ZmluYWw=\"")), examples = Seq("'final'.encode()")), + insertText = "encode()", detail = "", label = "encode", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BASE64BINARY), inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def encode(): Seq[FhirPathResult] = { checkSingleString() current.headOption.map(c => Seq(FhirPathString(Base64.getEncoder.encodeToString(c.asInstanceOf[FhirPathString].s.getBytes("UTF-8"))))).getOrElse(Nil) @@ -1068,8 +1202,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP /** * Tree navigation function http://hl7.org/fhirpath/#tree-navigation */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns a collection with all immediate child nodes of all items in the input collection.\n\n\uD83D\uDD19 _@return_\n```json\n[\n {\n \"linkId\": \"1\",\n \"text\": \"Do you have allergies?\",\n \"type\": \"boolean\"\n },\n {\n \"linkId\": \"2\",\n \"text\": \"General health questions\",\n \"type\": \"group\"\n }\n]\n``` \n\uD83D\uDCA1 **E.g.** Questionnaire.children().select(item)", - insertText = "children()", detail = "", label = "children", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns a collection with all immediate child nodes of all items in the input collection.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""[{"linkId": "1","text": "Do you have allergies?","type": "boolean"},{"linkId": "2","text": "General health questions","type": "group"}]""")), examples = Seq("Questionnaire.children().select(item)")), + insertText = "children()", detail = "", label = "children", kind = "Method", returnType = Seq(), inputType = Seq() + ) def children(): Seq[FhirPathResult] = { current .filter(_.isInstanceOf[FhirPathComplex]) @@ -1077,22 +1213,28 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP .flatMap(pc => pc.json.obj.map(_._2).flatMap(i => FhirPathValueTransformer.transform(i, context.isContentFhir))) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the input string with all characters converted to upper case.\n\n\uD83D\uDD19 _@return_\n```\nABCDEFG\n``` \n\uD83D\uDCA1 **E.g.** ''abcdefg'.upper()", - insertText = "upper()", detail = "", label = "upper", kind = "Method", returnType = Seq("string"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the input string with all characters converted to upper case.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("ABCDEFG")), examples = Seq("abcdefg'.upper()")), + insertText = "upper()", detail = "", label = "upper", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.STRING), inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def upper(): Seq[FhirPathResult] = { checkSingleString() current.headOption.map(c => Seq(FhirPathString(c.asInstanceOf[FhirPathString].s.toUpperCase))).getOrElse(Nil) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the input string with all characters converted to lower case.\n\n\uD83D\uDD19 _@return_\n```\nabcdefg\n``` \n\uD83D\uDCA1 **E.g.** ''ABCDEFG'.lower()", - insertText = "lower()", detail = "", label = "lower", kind = "Method", returnType = Seq("string"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the input string with all characters converted to lower case.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("abcdefg")), examples = Seq("ABCDEFG'.lower()")), + insertText = "lower()", detail = "", label = "lower", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.STRING), inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def lower(): Seq[FhirPathResult] = { checkSingleString() current.headOption.map(c => Seq(FhirPathString(c.asInstanceOf[FhirPathString].s.toLowerCase))).getOrElse(Nil) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns a collection with all descendant nodes of all items in the input collection.\n\n\uD83D\uDD19 _@return_\n```json\n[\n {\n \"linkId\": \"1\",\n \"text\": \"Do you have allergies?\",\n \"type\": \"boolean\"\n },\n {\n \"linkId\": \"2\",\n \"text\": \"General health questions\",\n \"type\": \"group\"\n },\n {\n \"linkId\": \"2.1\",\n \"text\": \"Do you have any chronic diseases?\",\n \"type\": \"boolean\"\n }\n]\n``` \n\uD83D\uDCA1 **E.g.** Questionnaire.descendants().select(item)", - insertText = "descendants()", detail = "", label = "descendants", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns a collection with all descendant nodes of all items in the input collection.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""[{"linkId": "1","text": "Do you have allergies?","type": "boolean"},{"linkId": "2","text": "General health questions","type": "group"},{"linkId": "2.1","text": "Do you have any chronic diseases?","type": "boolean"}]""")), examples = Seq("Questionnaire.descendants().select(item)")), + insertText = "descendants()", detail = "", label = "descendants", kind = "Method", returnType = Seq(), inputType = Seq() + ) def descendants(): Seq[FhirPathResult] = { val results = children() if (results.nonEmpty) @@ -1101,14 +1243,18 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP results } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns true if the input collection contains values.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** someCollection.hasValue()", - insertText = "hasValue()", detail = "", label = "hasValue", kind = "Method", returnType = Seq("boolean"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns true if the input collection contains values.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("someCollection.hasValue()")), + insertText = "hasValue()", detail = "", label = "hasValue", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq() + ) def hasValue(): Seq[FhirPathResult] = { Seq(FhirPathBoolean(current.nonEmpty)) } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns true if the engine executing the FHIRPath statement can compare the singleton Quantity with the singleton other Quantity and determine their relationship to each other.\n\n\uD83D\uDD19 _@return_\n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** someQuantity.comparable(otherQuantity)", - insertText = "comparable()", detail = "", label = "comparable", kind = "Method", returnType = Seq("boolean"), inputType = Seq("Quantity")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns true if the engine executing the FHIRPath statement can compare the singleton Quantity with the singleton other Quantity and determine their relationship to each other.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "thatQuantity", detail = "The other Quantity to compare against.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("true or false")), examples = Seq("someQuantity.comparable(otherQuantity)")), + insertText = "comparable()", detail = "", label = "comparable", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), inputType = Seq(FHIR_DATA_TYPES.QUANTITY) + ) def comparable(thatQuantity: ExpressionContext): Seq[FhirPathResult] = { if (current.length > 1) throw new FhirPathException(s"Invalid function call 'comparable' on multi item collection!") val that = new FhirPathExpressionEvaluator(context, context._this).visit(thatQuantity) match { @@ -1124,20 +1270,28 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP } } - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the low boundary of the input that this function is called upon. The input can be a decimal number, time or dateTime.\n\n\uD83D\uDD19 _@return_\n```\n2.38550, 2015-01-01T00:00:00, etc.\n``` \n\uD83D\uDCA1 **E.g.** 2.386.lowBoundary(), 2015.utl:toFhirDateTime('yyyy').lowBoundary(), etc.", - insertText = "lowBoundary()", detail = "", label = "lowBoundary", kind = "Method", returnType = Seq("number", "time", "date", "dateTime"), inputType = Seq("number", "time", "date", "dateTime")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the low boundary of the input that this function is called upon. The input can be a decimal number, time or dateTime.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("2.38550, 2015-01-01T00:00:00, etc.")), examples = Seq("2.386.lowBoundary(), 2015.utl:toFhirDateTime('yyyy').lowBoundary(), etc.")), + insertText = "lowBoundary()", detail = "", label = "lowBoundary", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.TIME, FHIR_DATA_TYPES.DATE, FHIR_DATA_TYPES.DATETIME), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.TIME, FHIR_DATA_TYPES.DATE, FHIR_DATA_TYPES.DATETIME) + ) def lowBoundary(): Seq[FhirPathResult] = lowBoundary(None) - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the low boundary of the input that this function is called upon by optionally accepting a precision for boundary calculation. The input can be a decimal number, time or dateTime.\n\n\uD83D\uDCDD _@param_ **`precisionExpr`** \nThe precision expression.\n\n\uD83D\uDD19 _@return_\n```\n2.3855000, 2018-01, etc.\n``` \n\uD83D\uDCA1 **E.g.** 2.386.lowBoundary(7), '2018'.utl:toFhirDateTime('yyyy').lowBoundary(6), etc.", - insertText = "lowBoundary()", detail = "", label = "lowBoundary", kind = "Method", returnType = Seq("number", "time", "date", "dateTime"), inputType = Seq("number", "time", "date", "dateTime")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the low boundary of the input that this function is called upon by optionally accepting a precision for boundary calculation. The input can be a decimal number, time or dateTime.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "precisionExpr", detail = "The precision expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("2.3855000, 2018-01, etc.")), examples = Seq("2.386.lowBoundary(7), '2018'.utl:toFhirDateTime('yyyy').lowBoundary(6), etc.")), + insertText = "lowBoundary()", detail = "", label = "lowBoundary", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.TIME, FHIR_DATA_TYPES.DATE, FHIR_DATA_TYPES.DATETIME), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.TIME, FHIR_DATA_TYPES.DATE, FHIR_DATA_TYPES.DATETIME) + ) def lowBoundary(precisionExpr: ExpressionContext): Seq[FhirPathResult] = lowBoundary(Some(precisionExpr)) - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the high boundary of the input that this function is called upon. The input can be a decimal number, time or dateTime.\n\n\uD83D\uDD19 _@return_\n```\n2.38650, 2015-12-31T23:59:59, etc.\n``` \n\uD83D\uDCA1 **E.g.** 2.386.highBoundary(), 2015.utl:toFhirDateTime('yyyy').highBoundary(), etc.", - insertText = "highBoundary()", detail = "", label = "highBoundary", kind = "Method", returnType = Seq("number", "time", "date", "dateTime"), inputType = Seq("number", "time", "date", "dateTime")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the high boundary of the input that this function is called upon. The input can be a decimal number, time or dateTime.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("2.38650, 2015-12-31T23:59:59, etc.")), examples = Seq("2.386.highBoundary(), 2015.utl:toFhirDateTime('yyyy').highBoundary(), etc.")), + insertText = "highBoundary()", detail = "", label = "highBoundary", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.TIME, FHIR_DATA_TYPES.DATE, FHIR_DATA_TYPES.DATETIME), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.TIME, FHIR_DATA_TYPES.DATE, FHIR_DATA_TYPES.DATETIME) + ) def highBoundary(): Seq[FhirPathResult] = highBoundary(None) - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the high boundary of the input that this function is called upon by optionally accepting a precision for boundary calculation. The input can be a decimal number, time or dateTime.\n\n\uD83D\uDCDD _@param_ **`precisionExpr`** \nThe precision expression.\n\n\uD83D\uDD19 _@return_\n```\n2.3865000, 2018-12, etc.\n``` \n\uD83D\uDCA1 **E.g.** 2.386.highBoundary(7), '2018'.utl:toFhirDateTime('yyyy').highBoundary(6), etc.", - insertText = "highBoundary()", detail = "", label = "highBoundary", kind = "Method", returnType = Seq("number", "time", "date", "dateTime"), inputType = Seq("number", "time", "date", "dateTime")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the high boundary of the input that this function is called upon by optionally accepting a precision for boundary calculation. The input can be a decimal number, time, or dateTime.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "precisionExpr", detail = "The precision expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("2.3865000, 2018-12, etc.")), examples = Seq("2.386.highBoundary(7), '2018'.utl:toFhirDateTime('yyyy').highBoundary(6), etc.")), + insertText = "highBoundary()", detail = "", label = "highBoundary", kind = "Method", returnType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.TIME, FHIR_DATA_TYPES.DATE, FHIR_DATA_TYPES.DATETIME), inputType = Seq(FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.TIME, FHIR_DATA_TYPES.DATE, FHIR_DATA_TYPES.DATETIME) + ) def highBoundary(precisionExpr: ExpressionContext): Seq[FhirPathResult] = highBoundary(Some(precisionExpr)) /** @@ -1340,8 +1494,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * @param initValueExpr Given initial value for aggregation * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Performs general-purpose aggregation by evaluating the aggregator expression for each element of the input collection.\n\n\uD83D\uDCDD _@param_ **`aggExpr`** \nThe aggregation expression.\n\n\uD83D\uDCDD _@param_ **`initValueExpr`** \nGiven initial value for aggregation.\n\n\uD83D\uDD19 _@return_\n```json\n{\n \"total\": 15\n}\n``` \n\uD83D\uDCA1 **E.g.** value.aggregate($this + $total, 0)", - insertText = "aggregate(,)", detail = "", label = "aggregate", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Performs general-purpose aggregation by evaluating the aggregator expression for each element of the input collection.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "aggExpr", detail = "The aggregation expression.", None), FhirPathFunctionParameter(name = "initValueExpr", detail = "Given initial value for aggregation.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""{"total": 15}""")), examples = Seq("value.aggregate($this + $total, 0)")), + insertText = "aggregate(,)", detail = "", label = "aggregate", kind = "Method", returnType = Seq(), inputType = Seq() + ) def aggregate(aggExpr: ExpressionContext, initValueExpr: ExpressionContext): Seq[FhirPathResult] = { val initValue = new FhirPathExpressionEvaluator(context, current).visit(initValueExpr) if (initValue.length > 1) @@ -1376,8 +1532,10 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP * @param aggExpr Aggregation expression * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Performs general-purpose aggregation by evaluating the aggregator expression for each element of the input collection.\n\n\uD83D\uDCDD _@param_ **`aggExpr`** \nThe aggregation expression.\n\n\uD83D\uDD19 _@return_\n```json\n{\n \"total\": 15\n}\n``` \n\uD83D\uDCA1 **E.g.** value.aggregate($this + $total)", - insertText = "aggregate()", detail = "", label = "aggregate", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Performs general-purpose aggregation by evaluating the aggregator expression for each element of the input collection.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "aggExpr", detail = "The aggregation expression.", None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""{"total": 15}""")), examples = Seq("value.aggregate($this + $total)")), + insertText = "aggregate()", detail = "", label = "aggregate", kind = "Method", returnType = Seq(), inputType = Seq() + ) def aggregate(aggExpr: ExpressionContext): Seq[FhirPathResult] = { handleAggregate(context, aggExpr) } @@ -1385,23 +1543,31 @@ class FhirPathFunctionEvaluator(context: FhirPathEnvironment, current: Seq[FhirP /** * Utility functions http://hl7.org/fhirpath/#utility-functions */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the current date.\n\n\uD83D\uDD19 _@return_\n```json\n{\n \"date\": \"2024-07-19\"\n}\n``` \n\uD83D\uDCA1 **E.g.** today()", - insertText = "today()", detail = "", label = "today", kind = "Function", returnType = Seq("dateTime"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the current date.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""{"date": "2024-07-19"}""")), examples = Seq("today()")), + insertText = "today()", detail = "", label = "today", kind = "Function", returnType = Seq(FHIR_DATA_TYPES.DATETIME), inputType = Seq() + ) def today(): Seq[FhirPathResult] = Seq(FhirPathDateTime(LocalDate.now())) - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the current date and time, including timezone offset.\n\n\uD83D\uDD19 _@return_\n```json\n{\n \"dateTime\": \"2024-07-19T14:23:45.678+02:00\"\n}\n``` \n\uD83D\uDCA1 **E.g.** now()", - insertText = "now()", detail = "", label = "now", kind = "Function", returnType = Seq("dateTime"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Returns the current date and time, including timezone offset.", usageWarnings = None, parameters = None, returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""{"dateTime": "2024-07-19T14:23:45.678+02:00"}""")), examples = Seq("now()")), + insertText = "now()", detail = "", label = "now", kind = "Function", returnType = Seq(FHIR_DATA_TYPES.DATETIME), inputType = Seq() + ) def now(): Seq[FhirPathResult] = Seq(FhirPathDateTime(ZonedDateTime.now())) - @FhirPathFunction(documentation = "\uD83D\uDCDC Adds a String representation of the input collection to the diagnostic log, using the name argument as the name in the log.\n\n\uD83D\uDCDD _@param_ **`nameExpr`** \nThe name expression.\n\n\uD83D\uDD19 _@return_\n```json\n{\n \"trace\": \"Logging collection with name: unmatched\",\n \"collection\": [1, 2, 3]\n}\n``` \n\uD83D\uDCA1 **E.g.** contained.where(criteria).trace('unmatched').empty()", - insertText = "trace()", detail = "", label = "trace", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Adds a String representation of the input collection to the diagnostic log, using the name argument as the name in the log.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "nameExpr", detail = "The name expression.", None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""{"trace": "Logging collection with name: unmatched","collection": [1, 2, 3]}""")), examples = Seq("contained.where(criteria).trace('unmatched').empty()")), + insertText = "trace()", detail = "", label = "trace", kind = "Method", returnType = Seq(), inputType = Seq() + ) def trace(nameExpr: ExpressionContext): Seq[FhirPathResult] = { //TODO log the current value with the given name current } - @FhirPathFunction(documentation = "\uD83D\uDCDC Adds a String representation of the input collection to the diagnostic log, using the name argument as the name in the log and the other argument as additional information.\n\n\uD83D\uDCDD _@param_ **`nameExpr`** \nThe name expression.\n\n\uD83D\uDCDD _@param_ **`othExpr`** \nThe other expression.\n\n\uD83D\uDD19 _@return_\n```json\n{\n \"trace\": \"Logging collection with name: unmatched, additional info: id\",\n \"collection\": [1, 2, 3]\n}\n``` \n\uD83D\uDCA1 **E.g.** contained.where(criteria).trace('unmatched', id).empty()", - insertText = "trace(,)", detail = "", label = "trace", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation(detail = "Adds a String representation of the input collection to the diagnostic log, using the name argument as the name in the log and the other argument as additional information.", usageWarnings = None, parameters = Some(Seq(FhirPathFunctionParameter(name = "nameExpr", detail = "The name expression.", examples = None), FhirPathFunctionParameter(name = "othExpr", detail = "The other expression.", examples = None))), returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("""{"trace": "Logging collection with name: unmatched, additional info: id","collection": [1, 2, 3]}""")), examples = Seq("contained.where(criteria).trace('unmatched', id).empty()")), + insertText = "trace(,)", detail = "", label = "trace", kind = "Method", returnType = Seq(), inputType = Seq() + ) def trace(nameExpr: ExpressionContext, othExpr: ExpressionContext): Seq[FhirPathResult] = { current } diff --git a/onfhir-path/src/main/scala/io/onfhir/path/FhirPathIdentityServiceFunctions.scala b/onfhir-path/src/main/scala/io/onfhir/path/FhirPathIdentityServiceFunctions.scala index 80e2b281..992fafe1 100644 --- a/onfhir-path/src/main/scala/io/onfhir/path/FhirPathIdentityServiceFunctions.scala +++ b/onfhir-path/src/main/scala/io/onfhir/path/FhirPathIdentityServiceFunctions.scala @@ -1,7 +1,8 @@ package io.onfhir.path +import io.onfhir.api.FHIR_DATA_TYPES import io.onfhir.api.service.IFhirIdentityService -import io.onfhir.path.annotation.FhirPathFunction +import io.onfhir.path.annotation.{FhirPathFunction, FhirPathFunctionDocumentation, FhirPathFunctionParameter, FhirPathFunctionReturn} import io.onfhir.path.grammar.FhirPathExprParser.ExpressionContext import scala.concurrent.Await @@ -20,8 +21,39 @@ class FhirPathIdentityServiceFunctions(context: FhirPathEnvironment) extends Abs * @param identifierValueExpr Business identifier value (Identifier.value) * @return Identifier for the resource e.g. Patient/455435464698 */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Resolves the given business identifier and return the FHIR Resource identifier (together with the resource type) by using the supplied identity service. \nâš \uFE0F To use this function, the mapping must be executed with a mapping job that includes a configured Identity Service.\n\n\uD83D\uDCDD _@param_ **`resourceType`** \nThe FHIR resource type for which the business identifier is being resolved. This should be a valid FHIR resource type.\n\n\uD83D\uDCDD _@param_ **`identifierValue`** \nThe value of the business identifier value (Identifier.value) that needs to be resolved.\n\n\uD83D\uDD19 _@return_ \nThe method returns the identifier for the resource in the format `/`.\n```json\n\"Patient/455435464698\"\n``` \n\uD83D\uDCA1 **E.g.** idxs:resolveIdentifier('Patient', '12345')", - insertText = "idxs:resolveIdentifier(, )",detail = "idxs", label = "idxs:resolveIdentifier", kind = "Function", returnType = Seq("string"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Resolves the given business identifier and returns the FHIR Resource identifier (together with the resource type) by using the supplied identity service.", + usageWarnings = Some(Seq("To use this function, the mapping must be executed with a mapping job that includes a configured Identity Service.")), + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "resourceType", + detail = "The FHIR resource type for which the business identifier is being resolved. This should be a valid FHIR resource type.", + examples = None + ), + FhirPathFunctionParameter( + name = "identifierValue", + detail = "The value of the business identifier value (Identifier.value) that needs to be resolved.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = Some("The method returns the identifier for the resource in the format"), + examples = Seq( + "\"Patient/455435464698\"" + ) + ), + examples = Seq( + "idxs:resolveIdentifier('Patient', '12345')" + ) + ), + insertText = "idxs:resolveIdentifier(, )", + detail = "idxs", + label = "idxs:resolveIdentifier", + kind = "Function", + returnType = Seq(FHIR_DATA_TYPES.STRING), + inputType = Seq() + ) def resolveIdentifier(resourceTypeExpr: ExpressionContext, identifierValueExpr: ExpressionContext): Seq[FhirPathResult] = resolveIdentifier(resourceTypeExpr, identifierValueExpr, None) /** @@ -32,8 +64,44 @@ class FhirPathIdentityServiceFunctions(context: FhirPathEnvironment) extends Abs * @param identifierSystemExpr Business identifier system (Identifier.system) * @return Identifier for the resource e.g. Patient/455435464698 */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Resolves the given business identifier+system and return the FHIR Resource identifier (together with the resource type) by using the supplied identity service. \nâš \uFE0F To use this function, the mapping must be executed with a mapping job that includes a configured Identity Service.\n\n\uD83D\uDCDD _@param_ **`resourceType`** \nThe FHIR resource type for which the business identifier is being resolved. This should be a valid FHIR resource type.\n\n\uD83D\uDCDD _@param_ **`identifierValue`** \nThe value of the business identifier value (Identifier.value) that needs to be resolved.\n\n\uD83D\uDCDD _@param_ **`identifierSystem`** \nThe value of the business identifier system (Identifier.system) that needs to be resolved.\n\n\uD83D\uDD19 _@return_ \nThe method returns the identifier for the resource in the format `/`.\n```json\n\"Patient/455435464698\"\n``` \n\uD83D\uDCA1 **E.g.** idxs:resolveIdentifier('Patient', '12345')", - insertText = "idxs:resolveIdentifier(, , )",detail = "idxs", label = "idxs:resolveIdentifier", kind = "Function", returnType = Seq("string"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Resolves the given business identifier+system and returns the FHIR Resource identifier (together with the resource type) by using the supplied identity service.", + usageWarnings = Some(Seq("To use this function, the mapping must be executed with a mapping job that includes a configured Identity Service.")), + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "resourceType", + detail = "The FHIR resource type for which the business identifier is being resolved. This should be a valid FHIR resource type.", + examples = None + ), + FhirPathFunctionParameter( + name = "identifierValue", + detail = "The value of the business identifier value (Identifier.value) that needs to be resolved.", + examples = None + ), + FhirPathFunctionParameter( + name = "identifierSystem", + detail = "The value of the business identifier system (Identifier.system) that needs to be resolved.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = Some("The method returns the identifier for the resource in the format"), + examples = Seq( + "\"Patient/455435464698\"" + ) + ), + examples = Seq( + "idxs:resolveIdentifier('Patient', '12345', 'http://example.com')" + ) + ), + insertText = "idxs:resolveIdentifier(, , )", + detail = "idxs", + label = "idxs:resolveIdentifier", + kind = "Function", + returnType = Seq(FHIR_DATA_TYPES.STRING), + inputType = Seq() + ) def resolveIdentifier(resourceTypeExpr: ExpressionContext, identifierValueExpr: ExpressionContext, identifierSystemExpr: ExpressionContext): Seq[FhirPathResult] = resolveIdentifier(resourceTypeExpr,identifierValueExpr,Some(identifierSystemExpr)) /** diff --git a/onfhir-path/src/main/scala/io/onfhir/path/FhirPathNavFunctions.scala b/onfhir-path/src/main/scala/io/onfhir/path/FhirPathNavFunctions.scala index 827bb37c..f9da9add 100644 --- a/onfhir-path/src/main/scala/io/onfhir/path/FhirPathNavFunctions.scala +++ b/onfhir-path/src/main/scala/io/onfhir/path/FhirPathNavFunctions.scala @@ -1,6 +1,6 @@ package io.onfhir.path -import io.onfhir.path.annotation.FhirPathFunction +import io.onfhir.path.annotation.{FhirPathFunction, FhirPathFunctionDocumentation, FhirPathFunctionParameter, FhirPathFunctionReturn} import io.onfhir.path.grammar.FhirPathExprParser.ExpressionContext /** @@ -15,8 +15,32 @@ class FhirPathNavFunctions(context:FhirPathEnvironment, current:Seq[FhirPathResu * @param elseExpr * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC If the current expression returns Nil, then evaluates the else expression from start, otherwise returns the current.\n\n\uD83D\uDCDD _@param_ **`elseExpr`** \nThe else expression to be evaluated if the current expression returns Nil.\n\n\uD83D\uDD19 _@return_ \nCurrent expression if it is not Nil, else expression otherwise.\n\n\uD83D\uDCA1 **E.g.** startTime.nav:orElse(plannedTime)", - insertText = "nav:orElse()",detail = "nav", label = "nav:orElse", kind = "Method", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "If the current expression returns Nil, then evaluates the else expression from start, otherwise returns the current.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "elseExpr", + detail = "The else expression to be evaluated if the current expression returns Nil.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq("Current expression if it is not Nil, else expression otherwise.") + ), + examples = Seq( + "startTime.nav:orElse(plannedTime)" + ) + ), + insertText = "nav:orElse()", + detail = "nav", + label = "nav:orElse", + kind = "Method", + returnType = Seq(), + inputType = Seq() + ) def orElse(elseExpr:ExpressionContext):Seq[FhirPathResult] = { current match { case Nil => diff --git a/onfhir-path/src/main/scala/io/onfhir/path/FhirPathTerminologyServiceFunctions.scala b/onfhir-path/src/main/scala/io/onfhir/path/FhirPathTerminologyServiceFunctions.scala index 9550c66d..1dc7a038 100644 --- a/onfhir-path/src/main/scala/io/onfhir/path/FhirPathTerminologyServiceFunctions.scala +++ b/onfhir-path/src/main/scala/io/onfhir/path/FhirPathTerminologyServiceFunctions.scala @@ -1,9 +1,10 @@ package io.onfhir.path import akka.http.scaladsl.model.Uri +import io.onfhir.api.FHIR_DATA_TYPES import io.onfhir.api.service.IFhirTerminologyService import io.onfhir.api.util.FHIRUtil -import io.onfhir.path.annotation.FhirPathFunction +import io.onfhir.path.annotation.{FhirPathFunction, FhirPathFunctionDocumentation, FhirPathFunctionParameter, FhirPathFunctionReturn} import io.onfhir.path.grammar.FhirPathExprParser.ExpressionContext import io.onfhir.util.JsonFormatter.formats import org.json4s.JsonAST.{JArray, JBool, JObject, JString} @@ -29,8 +30,46 @@ class FhirPathTerminologyServiceFunctions(context:FhirPathEnvironment) extends A * @param paramsExpr A URL encoded string with other parameters for the validate-code operation (e.g. 'source=http://acme.org/valueset/23&target=http://acme.org/valueset/23') * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC This calls the Terminology Service $translate operation.\n\n\uD83D\uDCDD _@param_ **`conceptMapExpr`** \nEither an actual ConceptMap, or a canonical URL reference to a value set.\n\n\uD83D\uDCDD _@param_ **`codeExpr`** \nThe source to translate: a Coding or code.\n\n\uD83D\uDCDD _@param_ **`paramsExpr`** \nA URL encoded string with other parameters for the validate-code operation (e.g. 'source=http://acme.org/valueset/23&target=http://acme.org/valueset/23')\n\n\uD83D\uDD19 _@return_ \n```json\n{\n \"code\": \"12345\",\n \"system\": \"http://example.org/system\",\n \"display\": \"Example Display\"\n}\n```\n\uD83D\uDCA1 **E.g.** %terminologies.trms:translate('http://aiccelerate.eu/fhir/ConceptMap/labResultsConceptMap', Observation.code, 'conceptMapVersion=1.0')", - insertText = "%terminologies.translate(,,)",detail = "trms", label = "%terminologies.translate", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "This calls the Terminology Service $translate operation.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "conceptMapExpr", + detail = "Either an actual ConceptMap, or a canonical URL reference to a value set.", + examples = None + ), + FhirPathFunctionParameter( + name = "codeExpr", + detail = "The source to translate: a Coding or code.", + examples = None + ), + FhirPathFunctionParameter( + name = "paramsExpr", + detail = "A URL encoded string with other parameters for the validate-code operation.", + examples = Some(Seq( + "'source=http://acme.org/valueset/23&target=http://acme.org/valueset/23'" + )) + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + """{ "code": "12345", "system": "http://example.org/system", "display": "Example Display" }""" + ) + ), + examples = Seq( + "%terminologies.trms:translate('http://aiccelerate.eu/fhir/ConceptMap/labResultsConceptMap', Observation.code, 'conceptMapVersion=1.0')" + ) + ), + insertText = "%terminologies.translate(, , )", + detail = "trms", + label = "%terminologies.translate", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def translate(conceptMapExpr:ExpressionContext, codeExpr:ExpressionContext, paramsExpr:ExpressionContext):Seq[FhirPathResult] = { val terminologyService = checkTerminologyService() //Evaluate concept map url @@ -91,8 +130,41 @@ class FhirPathTerminologyServiceFunctions(context:FhirPathEnvironment) extends A * @param paramsExpr A URL encoded string with other parameters for the validate-code operation (e.g. 'source=http://acme.org/valueset/23&target=http://acme.org/valueset/23') * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC This calls the Terminology Service $translate operation without a concept map.\n\n\uD83D\uDCDD _@param_ **`codeExpr`** \nThe source to translate: a Coding or code.\n\n\uD83D\uDCDD _@param_ **`paramsExpr`** \nA URL encoded string with other parameters for the validate-code operation (e.g. 'source=http://acme.org/valueset/23&target=http://acme.org/valueset/23')\n\n\uD83D\uDD19 _@return_ \n```json\n{\n \"code\": \"12345\",\n \"system\": \"http://example.org/system\",\n \"display\": \"Example Display\"\n}\n```\n\uD83D\uDCA1 **E.g.** %terminologies.trms:translate(Observation.code, 'source=http://hus.fi/ValueSet/labResultCodes'&target=http://aiccelerate.eu/ValueSet/labResultCodes)", - insertText = "%terminologies.translate(,)",detail = "trms", label = "%terminologies.translate", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "This calls the Terminology Service $translate operation without a concept map.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "codeExpr", + detail = "The source to translate: a Coding or code.", + examples = None + ), + FhirPathFunctionParameter( + name = "paramsExpr", + detail = "A URL encoded string with other parameters for the validate-code operation.", + examples = Some(Seq( + "'source=http://acme.org/valueset/23&target=http://acme.org/valueset/23'" + )) + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + """{ "code": "12345", "system": "http://example.org/system", "display": "Example Display" }""" + ) + ), + examples = Seq( + "%terminologies.trms:translate(Observation.code, 'source=http://hus.fi/ValueSet/labResultCodes&target=http://aiccelerate.eu/ValueSet/labResultCodes')" + ) + ), + insertText = "%terminologies.translate(, )", + detail = "trms", + label = "%terminologies.translate", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def translate(codeExpr:ExpressionContext, paramsExpr:ExpressionContext):Seq[FhirPathResult] = { val terminologyService = checkTerminologyService() // Evaluate code @@ -151,8 +223,41 @@ class FhirPathTerminologyServiceFunctions(context:FhirPathEnvironment) extends A * @param paramsExpr Expression to evaluate a URL encoded string with other parameters for the lookup operation (e.g. 'date=2011-03-04&displayLanguage=en') * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC This calls the Terminology Service $lookup operation.\n\n\uD83D\uDCDD _@param_ **`codeExpr`** \nExpression to evaluate to a code, Coding or CodeableConcept.\n\n\uD83D\uDCDD _@param_ **`paramsExpr`** \nExpression to evaluate a URL encoded string with other parameters for the lookup operation (e.g. 'date=2011-03-04&displayLanguage=en')\n\n\uD83D\uDD19 _@return_ \n```json\n{\n \"code\": \"12345\",\n \"system\": \"http://example.org/system\",\n \"display\": \"Example Display\"\n}\n```\n\uD83D\uDCA1 **E.g.** %terminologies.trms:lookup(Observation.code.coding[0], 'displayLanguage=tr')", - insertText = "%terminologies.lookup(,)",detail = "trms", label = "%terminologies.lookup", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "This calls the Terminology Service $lookup operation.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "codeExpr", + detail = "Expression to evaluate to a code, Coding or CodeableConcept.", + examples = None + ), + FhirPathFunctionParameter( + name = "paramsExpr", + detail = "Expression to evaluate a URL encoded string with other parameters for the lookup operation.", + examples = Some(Seq( + "'date=2011-03-04&displayLanguage=en'" + )) + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + """{ "code": "12345", "system": "http://example.org/system", "display": "Example Display" }""" + ) + ), + examples = Seq( + "%terminologies.trms:lookup(Observation.code.coding[0], 'displayLanguage=tr')" + ) + ), + insertText = "%terminologies.lookup(, )", + detail = "trms", + label = "%terminologies.lookup", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def lookup(codeExpr:ExpressionContext, paramsExpr:ExpressionContext):Seq[FhirPathResult] = { val terminologyService = checkTerminologyService() // Evaluate code @@ -215,8 +320,44 @@ class FhirPathTerminologyServiceFunctions(context:FhirPathEnvironment) extends A * @param displayLanguageExpr Expression to evaluate optional displayLanguage * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Return the display string in preferred language for the given code. If code or system can not be found, or displayLanguage does not match with available ones return empty. If code, system or displayLanguage does not evaluate to a single string, throws error. \nâš \uFE0F A code system with specified URL **must** be available in the terminology service and the mapping job must be configured to use this terminology service to use this function.\n\n\uD83D\uDCDD _@param_ **`source_code`** \nSource code to find its display value.\n\n\uD83D\uDCDD _@param_ **`codeSystemUrl`** \nUnique code system URL from terminology service to be used to perform lookup operation.\n\n\uD83D\uDCDD _@param_ **`targetColumn`** \nFHIRPath string literal providing the name of the interested column from the code system. Mostly language name. E.g. 'en', 'de'\n\n\uD83D\uDD19 _@return_ \n```json\n\"Probe von der Haut\"\n```\n\n\uD83D\uDCA1 **E.g.** trms:lookupDisplay('C12', 'http://hus.fi/CodeSystem/labResults', 'tr')", - insertText = "trms:lookupDisplay(, , )",detail = "trms", label = "trms:lookupDisplay", kind = "Function", returnType = Seq("string"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Return the display string in preferred language for the given code. If code or system cannot be found, or displayLanguage does not match with available ones, return empty. If code, system, or displayLanguage does not evaluate to a single string, throws an error.", + usageWarnings = Some(Seq("A code system with the specified URL **must** be available in the terminology service, and the mapping job must be configured to use this terminology service to use this function.")), + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "source_code", + detail = "Source code to find its display value.", + examples = None + ), + FhirPathFunctionParameter( + name = "codeSystemUrl", + detail = "Unique code system URL from the terminology service to be used to perform the lookup operation.", + examples = None + ), + FhirPathFunctionParameter( + name = "targetColumn", + detail = "FHIRPath string literal providing the name of the interested column from the code system. Mostly language name.", + examples = Some(Seq("en", "de")) + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "\"Probe von der Haut\"" + ) + ), + examples = Seq( + "trms:lookupDisplay('C12', 'http://hus.fi/CodeSystem/labResults', 'tr')" + ) + ), + insertText = "trms:lookupDisplay(, , )", + detail = "trms", + label = "trms:lookupDisplay", + kind = "Function", + returnType = Seq(FHIR_DATA_TYPES.STRING), + inputType = Seq() + ) def lookupDisplay(codeExpr:ExpressionContext, systemExpr:ExpressionContext, displayLanguageExpr:ExpressionContext):Seq[FhirPathResult] = { val terminologyService = checkTerminologyService() val code = evaluateToSingleString(codeExpr) @@ -247,8 +388,39 @@ class FhirPathTerminologyServiceFunctions(context:FhirPathEnvironment) extends A * @param conceptMapUrlExpr Expression to evaluate the ConceptMap canonical url * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Translates the given Coding or CodeableConcept object according to the given conceptMap from terminology service and returns a list of Coding objects. Translates the given code+system according to the given conceptMap from terminology service and returns a list of Coding objects. \nâš \uFE0F A concept map with specified URL **must** be available in the terminology service and the mapping job must be configured to use this terminology service to use this function.\n\n\uD83D\uDCDD _@param_ **`codeExpr`** \n[Coding](https://build.fhir.org/datatypes.html#Coding) or [CodeableConcept](https://build.fhir.org/datatypes.html#CodeableConcept) object to be translated.\n\n\uD83D\uDCDD _@param_ **`conceptMapUrlExpr`** \nUnique concept map URL from terminology service to be used to translate.\n\n\uD83D\uDD19 _@return_ \n```json\n[\n {\n \"system\": \"target-system\",\n \"code\": \"target-code\",\n \"display\": \"target-display\"\n },\n ...\n]\n``` \n\n\uD83D\uDCA1 **E.g.** trms:translateToCoding(codingObject, 'https://www.ncbi.nlm.nih.gov/clinvar')", - insertText = "trms:translateToCoding(, )",detail = "trms", label = "trms:translateToCoding", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Translates the given Coding or CodeableConcept object according to the given conceptMap from the terminology service and returns a list of Coding objects. Translates the given code+system according to the given conceptMap from the terminology service and returns a list of Coding objects.", + usageWarnings = Some(Seq("A concept map with the specified URL **must** be available in the terminology service, and the mapping job must be configured to use this terminology service to use this function.")), + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "codeExpr", + detail = "[Coding](https://build.fhir.org/datatypes.html#Coding) or [CodeableConcept](https://build.fhir.org/datatypes.html#CodeableConcept) object to be translated.", + examples = None + ), + FhirPathFunctionParameter( + name = "conceptMapUrlExpr", + detail = "Unique concept map URL from the terminology service to be used.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "[\n {\n \"system\": \"target-system\",\n \"code\": \"target-code\",\n \"display\": \"target-display\"\n },\n ...\n]" + ) + ), + examples = Seq( + "trms:translateToCoding(codingObject, 'https://www.ncbi.nlm.nih.gov/clinvar')" + ) + ), + insertText = "trms:translateToCoding(, )", + detail = "trms", + label = "trms:translateToCoding", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def translateToCoding(codingExpr:ExpressionContext, conceptMapUrlExpr:ExpressionContext):Seq[FhirPathResult] = { val terminologyService = checkTerminologyService() val codingResult = evaluateCodeExpr(codingExpr) @@ -276,8 +448,43 @@ class FhirPathTerminologyServiceFunctions(context:FhirPathEnvironment) extends A * @param conceptMapUrlExpr Expression to evaluate the ConceptMap canonical url * @return Matching codes (in Coding data type) */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Translates the given code+system according to the given conceptMap from terminology service and returns a list of Coding objects. \nâš \uFE0F A concept map with specified URL **must** be available in the terminology service and the mapping job must be configured to use this terminology service to use this function.\n\n\uD83D\uDCDD _@param_ **`codeExpr`** \nSource code to be translated.\n\n\uD83D\uDCDD _@param_ **`systemExpr`** \nSource system URL to be translated.\n\n\uD83D\uDCDD _@param_ **`conceptMapUrlExpr`** \nUnique concept map URL from terminology service to be used to translate.\n\n\uD83D\uDD19 _@return_ \n```json\n[\n {\n \"system\": \"target-system\",\n \"code\": \"target-code\",\n \"display\": \"target-display\"\n },\n ...\n]\n``` \n\uD83D\uDCA1 **E.g.** trms:translateToCoding(code, 'http://terminology.hl7.org/CodeSystem/icd9cm', 'https://www.ncbi.nlm.nih.gov/clinvar')", - insertText = "trms:translateToCoding(, , )",detail = "trms", label = "trms:translateToCoding", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Translates the given code+system according to the given conceptMap from terminology service and returns a list of Coding objects.", + usageWarnings = Some(Seq("A concept map with the specified URL **must** be available in the terminology service, and the mapping job must be configured to use this terminology service to use this function.")), + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "codeExpr", + detail = "Source code to be translated.", + examples = None + ), + FhirPathFunctionParameter( + name = "systemExpr", + detail = "Source system URL to be translated.", + examples = None + ), + FhirPathFunctionParameter( + name = "conceptMapUrlExpr", + detail = "Unique concept map URL from terminology service to be used to translate.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq("[\n {\n \"system\": \"target-system\",\n \"code\": \"target-code\",\n \"display\": \"target-display\"\n },\n ...\n]" + ) + ), + examples = Seq( + "trms:translateToCoding(code, 'http://terminology.hl7.org/CodeSystem/icd9cm', 'https://www.ncbi.nlm.nih.gov/clinvar')" + ) + ), + insertText = "trms:translateToCoding(, , )", + detail = "trms", + label = "trms:translateToCoding", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def translateToCoding(codeExpr:ExpressionContext, systemExpr:ExpressionContext, conceptMapUrlExpr:ExpressionContext):Seq[FhirPathResult] = { val terminologyService = checkTerminologyService() val conceptMapUrl = evaluateToSingleString(conceptMapUrlExpr) @@ -308,8 +515,48 @@ class FhirPathTerminologyServiceFunctions(context:FhirPathEnvironment) extends A * @param targetValueSetUrlExpr Expression to evaluate to the target value set url * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Translates the given code+system according to the given source value set and optional target value set from terminology service and returns a list of Coding objects. \nâš \uFE0F A concept map with specified URL **must** be available in the terminology service and the mapping job must be configured to use this terminology service to use this function.\n\n\uD83D\uDCDD _@param_ **`codeExpr`** \nSource code to be translated.\n\n\uD83D\uDCDD _@param_ **`systemExpr`** \nSource system URL to be translated.\n\n\uD83D\uDCDD _@param_ **`sourceValueSetUrlExpr`** \nSource value set URL to be used to translate.\n\n\uD83D\uDCDD _@param_ **`targetValueSetUrlExpr`** \nTarget value set URL to be used to translate.\n\n\uD83D\uDD19 _@return_ \n```json\n[\n {\n \"system\": \"target-system\",\n \"code\": \"target-code\",\n \"display\": \"target-display\"\n },\n ...\n]\n``` \n\uD83D\uDCA1 **E.g.** trms:translateToCoding(code, 'https://system', 'https://sourceValueSetUrl', 'https://targetValueSetUrl')", - insertText = "trms:translateToCoding(, , , )",detail = "trms", label = "trms:translateToCoding", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Translates the given code+system according to the given source value set and optional target value set from terminology service and returns a list of Coding objects.", + usageWarnings = Some(Seq("A concept map with the specified URL **must** be available in the terminology service, and the mapping job must be configured to use this terminology service to use this function.")), + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "codeExpr", + detail = "Source code to be translated.", + examples = None + ), + FhirPathFunctionParameter( + name = "systemExpr", + detail = "Source system URL to be translated.", + examples = None + ), + FhirPathFunctionParameter( + name = "sourceValueSetUrlExpr", + detail = "Source value set URL to be used to translate.", + examples = None + ), + FhirPathFunctionParameter( + name = "targetValueSetUrlExpr", + detail = "Target value set URL to be used to translate.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq("[\n {\n \"system\": \"target-system\",\n \"code\": \"target-code\",\n \"display\": \"target-display\"\n },\n ...\n]" + ) + ), + examples = Seq( + "trms:translateToCoding(code, 'https://system', 'https://sourceValueSetUrl', 'https://targetValueSetUrl')" + ) + ), + insertText = "trms:translateToCoding(, , , )", + detail = "trms", + label = "trms:translateToCoding", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def translateToCoding( codeExpr:ExpressionContext, systemExpr:ExpressionContext, sourceValueSetUrlExpr:ExpressionContext, diff --git a/onfhir-path/src/main/scala/io/onfhir/path/FhirPathUtilFunctions.scala b/onfhir-path/src/main/scala/io/onfhir/path/FhirPathUtilFunctions.scala index d3fec24c..e1c0d38d 100644 --- a/onfhir-path/src/main/scala/io/onfhir/path/FhirPathUtilFunctions.scala +++ b/onfhir-path/src/main/scala/io/onfhir/path/FhirPathUtilFunctions.scala @@ -1,7 +1,8 @@ package io.onfhir.path +import io.onfhir.api.FHIR_DATA_TYPES import io.onfhir.api.util.FHIRUtil -import io.onfhir.path.annotation.FhirPathFunction +import io.onfhir.path.annotation.{FhirPathFunction, FhirPathFunctionDocumentation, FhirPathFunctionParameter, FhirPathFunctionReturn} import io.onfhir.path.grammar.FhirPathExprParser.ExpressionContext import org.json4s.{JArray, JField, JObject, JString, JValue} @@ -25,8 +26,21 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Generates an UUID.\n\n\uD83D\uDD19 _@return_ \n```\n\"3f12a3e4-74c2-48c1-9836-53c1c1016554\"\n``` \n\uD83D\uDCA1 **E.g.** utl:uuid()", - insertText = "utl:uuid()", detail = "utl", label = "utl:uuid", kind = "Function", returnType = Seq("string"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Generates an UUID.", + usageWarnings = None, + parameters = None, + returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("3f12a3e4-74c2-48c1-9836-53c1c1016554")), + examples = Seq("utl:uuid()") + ), + insertText = "utl:uuid()", + detail = "utl", + label = "utl:uuid", + kind = "Function", + returnType = Seq(FHIR_DATA_TYPES.STRING), + inputType = Seq() + ) def uuid(): Seq[FhirPathResult] = { Seq(FhirPathString(UUID.randomUUID().toString)) } @@ -36,8 +50,24 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Checks whether the given string or character starts with or is a letter.\n\n\uD83D\uDD19 _@return_ \n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** 'abc'.utl:isLetter()", - insertText = "utl:isLetter()", detail = "utl", label = "utl:isLetter", kind = "Method", returnType = Seq("boolean"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Checks whether the given string or character starts with or is a letter.", + usageWarnings = None, + parameters = None, + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq("true", "false") + ), + examples = Seq("'abc'.utl:isLetter()") + ), + insertText = "utl:isLetter()", + detail = "utl", + label = "utl:isLetter", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), + inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def isLetter(): Seq[FhirPathResult] = { current match { case Seq(FhirPathString(l)) => Seq(FhirPathBoolean(l.head.isLetter)) @@ -53,8 +83,21 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @example ' ali '.trim() --> 'ali' * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Trims the strings in the current set so that they do not contain whitespaces. If the string is all whitespaces then returns Nil.\n\n\uD83D\uDD19 _@return_ \n```\n\"ali\"\n``` \n\uD83D\uDCA1 **E.g.** ' ali '.utl:trim()", - insertText = "utl:trim()", detail = "utl", label = "utl:trim", kind = "Method", returnType = Seq("string"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Trims the strings in the current set so that they do not contain whitespaces. If the string is all whitespaces then returns Nil.", + usageWarnings = None, + parameters = None, + returnValue = FhirPathFunctionReturn(detail = None, examples = Seq("\"ali\"")), + examples = Seq("' ali '.utl:trim()") + ), + insertText = "utl:trim()", + detail = "utl", + label = "utl:trim", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.STRING), + inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def trim(): Seq[FhirPathResult] = { current.flatMap { case FhirPathString(s) => @@ -75,8 +118,34 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param ridExp Resource identifier(s) * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Creates FHIR Reference object(s) with given resource type and id(s). If ridExp returns Nil, the function also returns Nil.\n\n\uD83D\uDCDD _@param_ **`resourceTypeExp`** \nExpression to provide FHIR Resource type 'Patient'.\n\n\uD83D\uDCDD _@param_ **`ridExp`** \nResource identifier(s).\n\n\uD83D\uDD19 _@return_ \n```json\n[\n {\n \"reference\": \"Observation/123\"\n },\n {\n \"reference\": \"Observation/456\"\n }\n]\n```\n\uD83D\uDCA1 **E.g.** utl:createFhirReference('Observation', id)", - insertText = "utl:createFhirReference(, )", detail = "utl", label = "utl:createFhirReference", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Creates FHIR Reference object(s) with given resource type and id(s). If ridExp returns Nil, the function also returns Nil.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "resourceTypeExp", + detail = "Expression to provide FHIR Resource type 'Patient'.", + examples = None + ), + FhirPathFunctionParameter( + name = "ridExp", + detail = "Resource identifier(s).", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq("""[{"reference":"Observation/123"},{"reference":"Observation/456"}]""")), + examples = Seq("utl:createFhirReference('Observation', id)") + ), + insertText = "utl:createFhirReference(, )", + detail = "utl", + label = "utl:createFhirReference", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def createFhirReference(resourceTypeExp: ExpressionContext, ridExp: ExpressionContext): Seq[FhirPathResult] = { val rids = new FhirPathExpressionEvaluator(context, current).visit(ridExp) if (!rids.forall(_.isInstanceOf[FhirPathString])) @@ -103,8 +172,40 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param displayExpr Expression to give the display value (optional) * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Creates a FHIR Coding content with given system code and optional display. If system or code parameters return Nil, the function returns Nil. All parameters should return 0 or 1 string value.\n\n\uD83D\uDCDD _@param_ **`systemExp`** \nExpression to give the system value.\n\n\uD83D\uDCDD _@param_ **`codeExpr`** \nExpression to give the code value.\n\n\uD83D\uDCDD _@param_ **`displayExpr`** \nExpression to give the display value (optional).\n\n\uD83D\uDD19 _@return_ \n```json\n[\n {\n \"system\": \"http://snomed.info/sct\",\n \"code\": \"246103008\",\n \"display\": \"Certainty\"\n }\n]\n```\n\uD83D\uDCA1 **E.g.** utl:createFhirCoding('http://snomed.info/sct', '246103008', 'Certainty')", - insertText = "utl:createFhirCoding(, , )", detail = "utl", label = "utl:createFhirCoding", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Creates a FHIR Coding content with given system code and optional display. If system or code parameters return Nil, the function returns Nil. All parameters should return 0 or 1 string value.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "systemExp", + detail = "Expression to give the system value.", + examples = None + ), + FhirPathFunctionParameter( + name = "codeExpr", + detail = "Expression to give the code value.", + examples = None + ), + FhirPathFunctionParameter( + name = "displayExpr", + detail = "Expression to give the display value (optional).", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq("""[{"system":"http://snomed.info/sct","code":"246103008","display":"Certainty"}]""") + ), + examples = Seq("utl:createFhirCoding('http://snomed.info/sct', '246103008', 'Certainty')") + ), + insertText = "utl:createFhirCoding(, , )", + detail = "utl", + label = "utl:createFhirCoding", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def createFhirCoding(systemExp: ExpressionContext, codeExpr: ExpressionContext, displayExpr: ExpressionContext): Seq[FhirPathResult] = { val system = new FhirPathExpressionEvaluator(context, current).visit(systemExp) if (system.length > 1 || !system.forall(_.isInstanceOf[FhirPathString])) @@ -141,8 +242,40 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param displayExpr Expression to give the display value (optional) * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Create a FHIR CodeableConcept content with given system code and optional display. If system or code parameters return Nil, the function returns Nil. All parameters should return 0 or 1 string value.\n\n\uD83D\uDCDD _@param_ **`systemExp`** \nExpression to give the system value.\n\n\uD83D\uDCDD _@param_ **`codeExpr`** \nExpression to give the code value.\n\n\uD83D\uDCDD _@param_ **`displayExpr`** \nExpression to give the display value (optional).\n\n\uD83D\uDD19 _@return_ \n```json\n[\n {\n \"system\": \"http://snomed.info/sct\",\n \"code\": \"246103008\",\n \"display\": \"Certainty\"\n }\n]\n```\n\uD83D\uDCA1 **E.g.** utl:createFhirCodeableConcept('http://snomed.info/sct', '246103008', 'Certainty')", - insertText = "utl:createFhirCodeableConcept(, , )", detail = "utl", label = "utl:createFhirCodeableConcept", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Create a FHIR CodeableConcept content with given system code and optional display. If system or code parameters return Nil, the function returns Nil. All parameters should return 0 or 1 string value.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "systemExp", + detail = "Expression to give the system value.", + examples = None + ), + FhirPathFunctionParameter( + name = "codeExpr", + detail = "Expression to give the code value.", + examples = None + ), + FhirPathFunctionParameter( + name = "displayExpr", + detail = "Expression to give the display value (optional).", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq("""[{"system":"http://snomed.info/sct","code":"246103008","display":"Certainty"}]""") + ), + examples = Seq("utl:createFhirCodeableConcept('http://snomed.info/sct', '246103008', 'Certainty')") + ), + insertText = "utl:createFhirCodeableConcept(, , )", + detail = "utl", + label = "utl:createFhirCodeableConcept", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def createFhirCodeableConcept(systemExp: ExpressionContext, codeExpr: ExpressionContext, displayExpr: ExpressionContext): Seq[FhirPathResult] = { val system = new FhirPathExpressionEvaluator(context, current).visit(systemExp) if (system.length > 1 || !system.forall(_.isInstanceOf[FhirPathString])) @@ -186,8 +319,35 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param unitExpr Expression for quantity unit * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Creates FHIR Quantity json object with given value and unit (system or code not set). If value expression returns Nil, the function also returns Nil.\n\n\uD83D\uDCDD _@param_ **`valueExpr`** \nExpression for quantity value.\n\n\uD83D\uDCDD _@param_ **`unitExpr`** \nExpression for quantity unit.\n\n\uD83D\uDD19 _@return_ \n```json\n[\n {\n \"value\": 1,\n \"unit\": \"mg\"\n }\n]\n```\n\uD83D\uDCA1 **E.g.** utl:createFhirQuantity(1, 'mg')", - insertText = "utl:createFhirQuantity(, )", detail = "utl", label = "utl:createFhirQuantity", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Creates FHIR Quantity json object with given value and unit (system or code not set). If value expression returns Nil, the function also returns Nil.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "valueExpr", + detail = "Expression for quantity value.", + examples = None + ), + FhirPathFunctionParameter( + name = "unitExpr", + detail = "Expression for quantity unit.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq("""[{"value": 1, "unit": "mg"}]""") + ), + examples = Seq("utl:createFhirQuantity(1, 'mg')") + ), + insertText = "utl:createFhirQuantity(, )", + detail = "utl", + label = "utl:createFhirQuantity", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def createFhirQuantity(valueExpr: ExpressionContext, unitExpr: ExpressionContext): Seq[FhirPathResult] = { val value = handleFhirQuantityValue(valueExpr) val unit = new FhirPathExpressionEvaluator(context, current).visit(unitExpr) @@ -209,8 +369,40 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param codeExpr Expression to return the the unit * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Creates FHIR Quantity json object with given value, system and unit. If any parameter expression returns Nil, the function will also return Nil.\n\n\uD83D\uDCDD _@param_ **`valueExpr`** \nExpression to return the quantity value.\n\n\uD83D\uDCDD _@param_ **`systemExpr`** \nExpression to return the system for the unit.\n\n\uD83D\uDCDD _@param_ **`codeExpr`** \nExpression to return the unit.\n\n\uD83D\uDD19 _@return_ \n```json\n[\n {\n \"value\": 15.2,\n \"unit\": \"mg\",\n \"system\": \"%ucum\"\n }\n]\n```\n\uD83D\uDCA1 **E.g.** utl:createFhirQuantity(15.2, %ucum, 'mg')", - insertText = "utl:createFhirQuantity(, , )", detail = "utl", label = "utl:createFhirQuantity", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Creates FHIR Quantity json object with given value, system, and unit. If any parameter expression returns Nil, the function will also return Nil.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "valueExpr", + detail = "Expression to return the quantity value.", + examples = None + ), + FhirPathFunctionParameter( + name = "systemExpr", + detail = "Expression to return the system for the unit.", + examples = None + ), + FhirPathFunctionParameter( + name = "codeExpr", + detail = "Expression to return the unit.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq("""[{"value": 15.2, "unit": "mg", "system": "%ucum"}]""") + ), + examples = Seq("utl:createFhirQuantity(15.2, %ucum, 'mg')") + ), + insertText = "utl:createFhirQuantity(, , )", + detail = "utl", + label = "utl:createFhirQuantity", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def createFhirQuantity(valueExpr: ExpressionContext, systemExpr: ExpressionContext, codeExpr: ExpressionContext): Seq[FhirPathResult] = { val value = handleFhirQuantityValue(valueExpr) @@ -238,8 +430,45 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param codeExpr Expression to return the unit code * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Creates FHIR Quantity json object with given value, unit and optional system and code. If value or unit parameter expression returns Nil, the function will also return Nil.\n\n\uD83D\uDCDD _@param_ **`valueExpr`** \nExpression to return the quantity value.\n\n\uD83D\uDCDD _@param_ **`unitExpr`** \nExpression to return the unit.\n\n\uD83D\uDCDD _@param_ **`systemExpr`** \nExpression to return the system for the unit.\n\n\uD83D\uDCDD _@param_ **`codeExpr`** \nExpression to return the unit code.\n\n\uD83D\uDD19 _@return_ \n```json\n[\n {\n \"value\": 15.2,\n \"unit\": \"mg\",\n \"system\": \"%ucum\",\n \"code\": \"mg\"\n }\n]\n```\n\uD83D\uDCA1 **E.g.** utl:createFhirQuantity(15.2, 'mg', %ucum, 'mg')", - insertText = "utl:createFhirQuantity(, , , )", detail = "utl", label = "utl:createFhirQuantity", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Creates FHIR Quantity json object with given value, unit and optional system and code. If value or unit parameter expression returns Nil, the function will also return Nil.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "valueExpr", + detail = "Expression to return the quantity value.", + examples = None + ), + FhirPathFunctionParameter( + name = "unitExpr", + detail = "Expression to return the unit.", + examples = None + ), + FhirPathFunctionParameter( + name = "systemExpr", + detail = "Expression to return the system for the unit.", + examples = None + ), + FhirPathFunctionParameter( + name = "codeExpr", + detail = "Expression to return the unit code.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq("""[{"value": 15.2, "unit": "mg", "system": "%ucum", "code": "mg"}]""") + ), + examples = Seq("utl:createFhirQuantity(15.2, 'mg', %ucum, 'mg')") + ), + insertText = "utl:createFhirQuantity(, , , )", + detail = "utl", + label = "utl:createFhirQuantity", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def createFhirQuantity(valueExpr: ExpressionContext, unitExpr: ExpressionContext, systemExpr: ExpressionContext, @@ -293,8 +522,24 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Checks if the given value is a FHIR Quantity expression e.g. 5.2, >7.1, etc. Returns true if given value is numeric, or given value evaluates to string but can be converted to numeric, or given value is string starting with comparators and the remaining string can be converted to numeric; otherwise returns false. If current value returns multiple values, throws exception.\n\n\uD83D\uDD19 _@return_ \n```\ntrue or false\n``` \n\uD83D\uDCA1 **E.g.** 5.utl:isFhirQuantityExpression()", - insertText = "utl:isFhirQuantityExpression()", detail = "utl", label = "utl:isFhirQuantityExpression", kind = "Method", returnType = Seq("boolean"), inputType = Seq("dateTime", "number", "string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Checks if the given value is a FHIR Quantity expression e.g. 5.2, >7.1, etc. Returns true if given value is numeric, or given value evaluates to string but can be converted to numeric, or given value is string starting with comparators and the remaining string can be converted to numeric; otherwise returns false. If current value returns multiple values, throws exception.", + usageWarnings = None, + parameters = None, + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq("true", "false") + ), + examples = Seq("5.utl:isFhirQuantityExpression()") + ), + insertText = "utl:isFhirQuantityExpression()", + detail = "utl", + label = "utl:isFhirQuantityExpression", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), + inputType = Seq(FHIR_DATA_TYPES.DATETIME, FHIR_DATA_TYPES.DECIMAL, FHIR_DATA_TYPES.STRING) + ) def isFhirQuantityExpression(): Seq[FhirPathResult] = { current match { case Nil => Nil @@ -328,8 +573,30 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param valueExpr FHIR Quantity expression with optional comparator * @return Seq of results where first element is the numeric value and second if exists is the comparator */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Parses a FHIR quantity expression e.g. >50.5, 42, etc. Returns a sequence of results where the first element is the numeric value and the second if exists is the comparator. If the given value is empty or not a quantity expression, returns Nil.\n\n\uD83D\uDCDD _@param_ **`valueExpr`** \nFHIR Quantity expression with optional comparator.\n\n\uD83D\uDD19 _@return_ \n```json\n{\n \"numericValue\": 50.5,\n \"comparator\": \">\",\n}\n```\n\uD83D\uDCA1 **E.g.** utl:parseFhirQuantityExpression('>50.5')", - insertText = "utl:parseFhirQuantityExpression()", detail = "utl", label = "utl:parseFhirQuantityExpression", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Parses a FHIR quantity expression e.g. >50.5, 42, etc. Returns a sequence of results where the first element is the numeric value and the second, if exists, is the comparator. If the given value is empty or not a quantity expression, returns Nil.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "valueExpr", + detail = "FHIR Quantity expression with optional comparator.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq("""[{"numericValue": 50.5, "comparator": ">"}]""") + ), + examples = Seq("utl:parseFhirQuantityExpression('>50.5')") + ), + insertText = "utl:parseFhirQuantityExpression()", + detail = "utl", + label = "utl:parseFhirQuantityExpression", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def parseFhirQuantityExpression(valueExpr: ExpressionContext): Seq[FhirPathResult] = { handleFhirQuantityValue(valueExpr) match { case None => Nil @@ -380,8 +647,39 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param toDate Other date expression * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Retrieves the duration between given FHIR dateTimes as FHIR Duration with a suitable duration unit (either minute, day, or month).\n\n\uD83D\uDCDD _@param_ **`fromDate`** \nGiven date expression.\n\n\uD83D\uDCDD _@param_ **`toDate`** \nOther date expression.\n\n\uD83D\uDD19 _@return_ \n```json\n{\n \"durationValue\": 30,\n \"unit\": \"d\"\n}\n```\n\uD83D\uDCA1 **E.g.** utl:parseFhirQuantityExpression('2020-04-20T10:30:00Z', '2020-05-20T10:30:00Z')", - insertText = "utl:getDurationAsQuantityObject(, )", detail = "utl", label = "utl:getDurationAsQuantityObject", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Retrieves the duration between given FHIR dateTimes as FHIR Duration with a suitable duration unit (either minute, day, or month).", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "fromDate", + detail = "Given date expression.", + examples = None + ), + FhirPathFunctionParameter( + name = "toDate", + detail = "Other date expression.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + """{"durationValue": 30,"unit": "d"}""" + ) + ), + examples = Seq( + "utl:getDurationAsQuantityObject('2020-04-20T10:30:00Z', '2020-05-20T10:30:00Z')" + ) + ), + insertText = "utl:getDurationAsQuantityObject(, )", + detail = "utl", + label = "utl:getDurationAsQuantityObject", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def getDurationAsQuantityObject(fromDate: ExpressionContext, toDate: ExpressionContext): Seq[FhirPathResult] = { val fdate: Option[Temporal] = new FhirPathExpressionEvaluator(context, current).visit(fromDate) match { case Seq(FhirPathDateTime(dt)) => Some(dt) @@ -466,8 +764,34 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param splitCharExpr Expression to return split character(s) * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Splits the current string value by given split character or string.\n\n\uD83D\uDCDD _@param_ **`splitCharExpr`** \nExpression to return split string(s).\n\n\uD83D\uDD19 _@return_ \n```json\n{\n \"first\",\n \"second\",\n \"third\"\n}\n```\n\uD83D\uDCA1 **E.g.** Observation.valueSampleData.data.utl:split(' ') --> Split by empty space", - insertText = "utl:split()", detail = "utl", label = "utl:split", kind = "Method", returnType = Seq("string"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Splits the current string value by given split character or string.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "splitCharExpr", + detail = "Expression to return split string(s).", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + """["first", "second", "third"]""" + ) + ), + examples = Seq( + "Observation.valueSampleData.data.utl:split(' ') --> Split by empty space" + ) + ), + insertText = "utl:split()", + detail = "utl", + label = "utl:split", + kind = "Method", + returnType = Seq(), + inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def split(splitCharExpr: ExpressionContext): Seq[FhirPathResult] = { val splitChar = @@ -499,8 +823,34 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param stopCharExpr List of stop characters * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Takes the prefix of a string until one of the given stop characters is encountered. If stopCharExpr returns empty list, returns the whole string. If given stopCharExpr does not return single character strings or current is not a string, throws an exception.\n\n\uD83D\uDCDD _@param_ **`stopCharExpr`** \nList of stop characters.\n\n\uD83D\uDD19 _@return_ \n```\n\"VERY LOW\"\n``` \n\uD83D\uDCA1 **E.g.** 'VERY LOW.'.utl:takeUntil('.' | '*')", - insertText = "utl:takeUntil()", detail = "utl", label = "utl:takeUntil", kind = "Method", returnType = Seq("string"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Takes the prefix of a string until one of the given stop characters is encountered. If stopCharExpr returns an empty list, returns the whole string. If given stopCharExpr does not return single-character strings or the current value is not a string, throws an exception.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "stopCharExpr", + detail = "List of stop characters.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "VERY LOW" + ) + ), + examples = Seq( + "'VERY LOW.'.utl:takeUntil('.' | '*')" + ) + ), + insertText = "utl:takeUntil()", + detail = "utl", + label = "utl:takeUntil", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.STRING), + inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def takeUntil(stopCharExpr: ExpressionContext): Seq[FhirPathResult] = { val stopChars: Set[Char] = (new FhirPathExpressionEvaluator(context, current) @@ -523,8 +873,39 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param toExpr End index (inclusive) * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Creates a list of integers between and including given two integers.\n\n\uD83D\uDCDD _@param_ **`fromExpr`** \nStart index (inclusive).\n\n\uD83D\uDCDD _@param_ **`toExpr`** \nEnd index (inclusive).\n\n\uD83D\uDD19 _@return_ \n```\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n``` \n\uD83D\uDCA1 **E.g.** utl:indices(1, 10)", - insertText = "utl:indices(, )", detail = "utl", label = "utl:indices", kind = "Function", returnType = Seq("integer"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Creates a list of integers between and including given two integers.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "fromExpr", + detail = "Start index (inclusive).", + examples = None + ), + FhirPathFunctionParameter( + name = "toExpr", + detail = "End index (inclusive).", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]" + ) + ), + examples = Seq( + "utl:indices(1, 10)" + ) + ), + insertText = "utl:indices(, )", + detail = "utl", + label = "utl:indices", + kind = "Function", + returnType = Seq(FHIR_DATA_TYPES.INTEGER), + inputType = Seq() + ) def indices(fromExpr: ExpressionContext, toExpr: ExpressionContext): Seq[FhirPathResult] = { val from = new FhirPathExpressionEvaluator(context, current).visit(fromExpr) if (from.length != 1 || !from.forall(_.isInstanceOf[FhirPathNumber])) @@ -544,8 +925,34 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param condExpr Boolean expression to check for each item * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns the indices (starting from 1) in the current sequence of results where the given expression returns true. If condition expression returns non boolean value, it returns false.\n\n\uD83D\uDCDD _@param_ **`condExpr`** \nBoolean expression to check for each item.\n\n\uD83D\uDD19 _@return_ \n```\n[1, 3, 5]\n``` \n\uD83D\uDCA1 **E.g.** Observation.code.coding.utl:indicesWhere($this.system='http://snomed.info/sct')", - insertText = "utl:indicesWhere()", detail = "utl", label = "utl:indicesWhere", kind = "Method", returnType = Seq("integer"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Returns the indices (starting from 1) in the current sequence of results where the given expression returns true. If condition expression returns a non-boolean value, it returns false.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "condExpr", + detail = "Boolean expression to check for each item.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "[1, 3, 5]" + ) + ), + examples = Seq( + "Observation.code.coding.utl:indicesWhere($this.system='http://snomed.info/sct')" + ) + ), + insertText = "utl:indicesWhere()", + detail = "utl", + label = "utl:indicesWhere", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.INTEGER), + inputType = Seq() + ) def indicesWhere(condExpr: ExpressionContext): Seq[FhirPathResult] = { current .zipWithIndex @@ -564,8 +971,34 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param separatorExp Expression to return a separator string * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Combines the current string results with the given separator and returns a string. If current is Nil, returns Nil.\n\n\uD83D\uDCDD _@param_ **`separatorExp`** \nExpression to return a separator string.\n\n\uD83D\uDD19 _@return_ \n```\n\"first | second | third\"\n``` \n\uD83D\uDCA1 **E.g.** code.utl:mkString(' | ')", - insertText = "utl:mkString()", detail = "utl", label = "utl:mkString", kind = "Method", returnType = Seq("string"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Combines the current string results with the given separator and returns a string. If current is Nil, returns Nil.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "separatorExp", + detail = "Expression to return a separator string.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "first | second | third" + ) + ), + examples = Seq( + "code.utl:mkString(' | ')" + ) + ), + insertText = "utl:mkString()", + detail = "utl", + label = "utl:mkString", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.STRING), + inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def mkString(separatorExp: ExpressionContext): Seq[FhirPathResult] = { if (!current.forall(_.isInstanceOf[FhirPathString])) throw new FhirPathException(s"Invalid function call 'mkString' on non string value(s)!") @@ -590,8 +1023,34 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param fhirPathExpression FHIR Path expression in string format * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Evaluates the given FHIR Path expression in string format on current content and context.\n\n\uD83D\uDCDD _@param_ **`fhirPathExpression`** \nFHIR Path expression in string format.\n\n\uD83D\uDD19 _@return_ \n```json\n{\n \"type\": \"Integer\",\n \"value\": 2\n}\n```\n\uD83D\uDCA1 **E.g.** utl:evaluateExpression('Observation.code[' & i &']') --> Return the ith code", - insertText = "utl:evaluateExpression()", detail = "utl", label = "utl:evaluateExpression", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Evaluates the given FHIR Path expression in string format on current content and context.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "fhirPathExpression", + detail = "FHIR Path expression in string format.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + """{"type": "Integer", "value": 2}""" + ) + ), + examples = Seq( + "utl:evaluateExpression('Observation.code[' & i &']') --> Return the ith code" + ) + ), + insertText = "utl:evaluateExpression()", + detail = "utl", + label = "utl:evaluateExpression", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def evaluateExpression(fhirPathExpression: ExpressionContext): Seq[FhirPathResult] = { val fhirPath = new FhirPathExpressionEvaluator(context, current).visit(fhirPathExpression) if (fhirPath.length != 1 || !fhirPath.forall(_.isInstanceOf[FhirPathString])) @@ -613,8 +1072,34 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param msgExpr Message for the exception * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Throws a FHIR Path exception with the given message.\n\n\uD83D\uDCDD _@param_ **`msgExpr`** \nMessage for the exception.\n\n\uD83D\uDD19 _@return_ \n```json\n{\n \"exception\": {\n \"message\": \"An error occurred\"\n }\n}\n```\n\uD83D\uDCA1 **E.g.** utl:throwException('An error occurred')", - insertText = "utl:throwException()", detail = "utl", label = "utl:throwException", kind = "Function", returnType = Seq(), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Throws a FHIR Path exception with the given message.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "msgExpr", + detail = "Message for the exception.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + """{"exception": {"message": "An error occurred"}}" """ + ) + ), + examples = Seq( + "utl:throwException('An error occurred')" + ) + ), + insertText = "utl:throwException()", + detail = "utl", + label = "utl:throwException", + kind = "Function", + returnType = Seq(), + inputType = Seq() + ) def throwException(msgExpr: ExpressionContext): Seq[FhirPathResult] = { val excMsg = new FhirPathExpressionEvaluator(context, current).visit(msgExpr) if (excMsg.length != 1 || !excMsg.head.isInstanceOf[FhirPathString]) @@ -631,8 +1116,44 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param period Period requested to calculate; either 'years','months','weeks','days','hours' or 'minutes' * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Returns a period between the FHIR date time given in fromDate and the FHIR date time given in toDate.\n\n\uD83D\uDCDD _@param_ **`fromDate`** \nGiven start date expression.\n\n\uD83D\uDCDD _@param_ **`toDate`** \nGiven end date expression.\n\n\uD83D\uDCDD _@param_ **`period`** \nPeriod requested to calculate; either 'years','months','weeks','days','hours' or 'minutes'.\n\n\uD83D\uDD19 _@return_ \n```json\n{\n \"period\": {\n \"value\": 3,\n \"unit\": \"years\",\n \"system\": \"http://unitsofmeasure.org\",\n \"code\": \"a\"\n }\n}\n```\n\uD83D\uDCA1 **E.g.** effectivePeriod.utl:getPeriod(start, @2020-09-07T10:00:00Z, 'years')", - insertText = "utl:getPeriod(, , )", detail = "utl", label = "utl:getPeriod", kind = "Method", returnType = Seq("number"), inputType = Seq("dateTime")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Returns a period between the FHIR date time given in fromDate and the FHIR date time given in toDate.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "fromDate", + detail = "Given start date expression.", + examples = None + ), + FhirPathFunctionParameter( + name = "toDate", + detail = "Given end date expression.", + examples = None + ), + FhirPathFunctionParameter( + name = "period", + detail = "Period requested to calculate; either 'years','months','weeks','days','hours' or 'minutes'.", + examples = None + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + """{"period": {"value": 3,"unit": "years","system": "http://unitsofmeasure.org","code": "a"}}""" + ) + ), + examples = Seq( + "effectivePeriod.utl:getPeriod(start, @2020-09-07T10:00:00Z, 'years')" + ) + ), + insertText = "utl:getPeriod(, , )", + detail = "utl", + label = "utl:getPeriod", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.DECIMAL), + inputType = Seq(FHIR_DATA_TYPES.DATETIME) + ) def getPeriod(fromDate: ExpressionContext, toDate: ExpressionContext, period: ExpressionContext): Seq[FhirPathResult] = { var fdate: Option[Temporal] = new FhirPathExpressionEvaluator(context, current).visit(fromDate) match { case Seq(FhirPathDateTime(dt)) => Some(dt) @@ -699,8 +1220,34 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param sourcePattern Java time date pattern e.g. dd.MM.yyyy * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Converts a given date string, based on the specified Java time date pattern, to a custom date string that is compliant with FHIR standards.\n\n\uD83D\uDCDD _@param_ **`sourcePattern`** \nThe Java time date pattern that defines the format of the input date string. This pattern must follow the Java SimpleDateFormat conventions. The pattern should be designed to match the format of the date strings that will be input to this function. For example:\n- yyyy-MM-dd for dates like 2021-12-25\n- dd/MM/yyyy for dates like 25/12/2024\n\n\uD83D\uDD19 _@return_ \n```json\n\"25/12/2024\"\n```\n\n\uD83D\uDCA1 **E.g.** '25.12.2024'.utl:toFhirDate('dd.MM.yyyy')", - insertText = "utl:toFhirDate()", detail = "utl", label = "utl:toFhirDate", kind = "Method", returnType = Seq("dateTime"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Converts a given date string, based on the specified Java time date pattern, to a custom date string that is compliant with FHIR standards.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "sourcePattern", + detail = "The Java time date pattern that defines the format of the input date string. This pattern must follow the Java SimpleDateFormat conventions. The pattern should be designed to match the format of the date strings that will be input to this function. For example:", + examples = Some(Seq("yyyy-MM-dd for dates like 2021-12-25", "dd/MM/yyyy for dates like 25/12/2024")) + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "\"25/12/2024\"" + ) + ), + examples = Seq( + "'25.12.2024'.utl:toFhirDate('dd.MM.yyyy')" + ) + ), + insertText = "utl:toFhirDate()", + detail = "utl", + label = "utl:toFhirDate", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.DATETIME), + inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def toFhirDate(sourcePattern: ExpressionContext): Seq[FhirPathResult] = { val pattern = new FhirPathExpressionEvaluator(context, current).visit(sourcePattern) if (pattern.isEmpty || !pattern.forall(_.isInstanceOf[FhirPathString])) { @@ -729,8 +1276,28 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Converts the current string value of time to the FHIR Time format. The current string representation of the time is expected to be in the following formats: \n- HH:mm:ss\n- HH:mm:ss.SSS\n\n\uD83D\uDD19 _@return_ \n```json\n\"22:10:45.123\"\n```\n\n\uD83D\uDCA1 **E.g.** '22:10:45'.utl:toFhirTime()", - insertText = "utl:toFhirTime()", detail = "utl", label = "utl:toFhirTime", kind = "Method", returnType = Seq("time"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Converts the current string value of time to the FHIR Time format. The current string representation of the time is expected to be in the following formats: \n- HH:mm:ss\n- HH:mm:ss.SSS", + usageWarnings = None, + parameters = None, + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "\"22:10:45.123\"" + ) + ), + examples = Seq( + "'22:10:45'.utl:toFhirTime()" + ) + ), + insertText = "utl:toFhirTime()", + detail = "utl", + label = "utl:toFhirTime", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.TIME), + inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def toFhirTime(): Seq[FhirPathResult] = { val patternsToTry = Seq("HH:mm:ss.SSS", "HH:mm:ss") _toFhirTime(patternsToTry) @@ -743,8 +1310,38 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param sourcePattern The format pattern of the time string to be converted. * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Converts a given time string, based on the specified format pattern, to a FHIR Time format, compliant with ISO 8601 standards.\n\n\uD83D\uDCDD _@param_ **`sourcePattern`** \nThe format pattern of the time string to be converted. Multiple formats at the same time are also supported using `|` character. The pattern should be designed to match the format of the time strings that will be input to this function. For example:\n- 'HH:mm:ss' for times such as 22:10:45\n- 'HH:mm' for times such as 22:10\n- 'HH:mm:ss.SSS' for times with milliseconds, such as 22:10:45.123\n\n\uD83D\uDD19 _@return_ \n```json\n\"22:10:45.123\"\n```\n\n\uD83D\uDCA1 **E.g.** '22:10:45'.utl:toFhirTime('HH:mm:ss' | 'HH:mm')", - insertText = "utl:toFhirTime()", detail = "utl", label = "utl:toFhirTime", kind = "Method", returnType = Seq("time"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Converts a given time string, based on the specified format pattern, to a FHIR Time format, compliant with ISO 8601 standards.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "sourcePattern", + detail = "The format pattern of the time string to be converted. Multiple formats at the same time are also supported using `|` character. The pattern should be designed to match the format of the time strings that will be input to this function. For example:", + examples = Some(Seq( + "'HH:mm:ss' for times such as 22:10:45", + "'HH:mm' for times such as 22:10", + "'HH:mm:ss.SSS' for times with milliseconds, such as 22:10:45.123" + )) + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "\"22:10:45.123\"" + ) + ), + examples = Seq( + "'22:10:45'.utl:toFhirTime('HH:mm:ss' | 'HH:mm')" + ) + ), + insertText = "utl:toFhirTime()", + detail = "utl", + label = "utl:toFhirTime", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.TIME), + inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def toFhirTime(sourcePattern: ExpressionContext): Seq[FhirPathResult] = { val pattern = new FhirPathExpressionEvaluator(context, current).visit(sourcePattern) if (pattern.isEmpty || !pattern.forall(_.isInstanceOf[FhirPathString])) { @@ -785,8 +1382,28 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Converts the current string value to the string representation of FHIR DateTime format, which complies with ISO 8601 standards. The current string representation of the date-time is expected to be in one of these formats:\n- \"yyyy-MM-dd HH:mm:ss\"\n- \"yyyy-MM-ddHH:mm:ss\"\n\n\uD83D\uDD19 _@return_ \n```json\n\"2012-01-13 22:10:45\"\n```\n\n\uD83D\uDCA1 **E.g.** '2012-01-13 22:10:45'.utl:toFhirDateTime()", - insertText = "utl:toFhirDateTime()", detail = "utl", label = "utl:toFhirDateTime", kind = "Method", returnType = Seq("dateTime"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Converts the current string value to the string representation of FHIR DateTime format, which complies with ISO 8601 standards. The current string representation of the date-time is expected to be in one of these formats:\n- \"yyyy-MM-dd HH:mm:ss\"\n- \"yyyy-MM-ddHH:mm:ss\"", + usageWarnings = None, + parameters = None, + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "\"2012-01-13 22:10:45\"" + ) + ), + examples = Seq( + "'2012-01-13 22:10:45'.utl:toFhirDateTime()" + ) + ), + insertText = "utl:toFhirDateTime()", + detail = "utl", + label = "utl:toFhirDateTime", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.DATETIME), + inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def toFhirDateTime(): Seq[FhirPathResult] = { val patternsToTry = Seq("yyyy-MM-dd HH:mm:ss", "yyyy-MM-ddHH:mm:ss") _toFhirDateTime(patternsToTry) @@ -799,8 +1416,37 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param sourcePattern The format pattern of the date-time string to be converted. * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Converts the current string value to the string representation of FHIR DateTime format, which complies with ISO 8601 standards. \n\n\uD83D\uDCDD _@param_ **`sourcePattern`** \nThe format pattern of the date-time string to be converted. Multiple formats at the same time are also supported using `|` character. The pattern should be designed to match the format of the time strings that will be input to this function. For example:\n- 'yyyy-MM-dd HH:mm:ss.SSS' for times such as 2024-01-13 22:10:45.167\n- 'yyyyMMdd.HH:mm:ss' for times such as 20240113.22:10:45\n\n\uD83D\uDD19 _@return_ \n```json\n\"2012-01-13 22:10:45\"\n```\n\n\uD83D\uDCA1 **E.g.** '20240113.22:10:45'.utl:toFhirDateTime('yyyy-MM-dd HH:mm:ss' | 'yyyyMMdd.HH:mm:ss')", - insertText = "utl:toFhirDateTime()", detail = "utl", label = "utl:toFhirDateTime", kind = "Method", returnType = Seq("dateTime"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Converts the current string value to the string representation of FHIR DateTime format, which complies with ISO 8601 standards.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "sourcePattern", + detail = "The format pattern of the date-time string to be converted. Multiple formats at the same time are also supported using `|` character. The pattern should be designed to match the format of the time strings that will be input to this function. For example:", + examples = Some(Seq( + "'yyyy-MM-dd HH:mm:ss.SSS' for times such as 2024-01-13 22:10:45.167", + "'yyyyMMdd.HH:mm:ss' for times such as 20240113.22:10:45" + )) + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "\"2012-01-13 22:10:45\"" + ) + ), + examples = Seq( + "'20240113.22:10:45'.utl:toFhirDateTime('yyyy-MM-dd HH:mm:ss' | 'yyyyMMdd.HH:mm:ss')" + ) + ), + insertText = "utl:toFhirDateTime()", + detail = "utl", + label = "utl:toFhirDateTime", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.DATETIME), + inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def toFhirDateTime(sourcePattern: ExpressionContext): Seq[FhirPathResult] = { val pattern = new FhirPathExpressionEvaluator(context, current).visit(sourcePattern) if (pattern.isEmpty || !pattern.forall(_.isInstanceOf[FhirPathString])) { @@ -817,8 +1463,46 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param zoneId Java ZoneId representation e.g. Europe/Berlin * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC Converts the current string value to the string representation of FHIR DateTime format (ISO DATE TIME) with the given time zone.\n\n\uD83D\uDCDD _@param_ **`sourcePattern`** \nThe format pattern of the date-time string to be converted. Multiple formats at the same time are also supported using `|` character. The pattern should be designed to match the format of the time strings that will be input to this function. For example:\n- 'yyyy-MM-dd HH:mm:ss.SSS' for times such as 2024-01-13 22:10:45.167\n- 'yyyyMMdd.HH:mm:ss' for times such as 20240113.22:10:45\n\n\uD83D\uDCDD _@param_ **`zoneId`** \nThe Java ZoneId representation of the time zone to be applied to the date-time string. For example:\n- Europe/Berlin\n- America/New_York\n- Asia/Tokyo\n\n\uD83D\uDD19 _@return_ \n```json\n\"2024-01-13 22:10:45\"\n```\n\n\uD83D\uDCA1 **E.g.** '20240113.22:10:45'.utl:toFhirDateTime('yyyy-MM-dd HH:mm:ss', 'Europe/Berlin')", - insertText = "utl:toFhirDateTime(, )", detail = "utl", label = "utl:toFhirDateTime", kind = "Method", returnType = Seq("dateTime"), inputType = Seq("string")) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "Converts the current string value to the string representation of FHIR DateTime format (ISO DATE TIME) with the given time zone.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "sourcePattern", + detail = "The format pattern of the date-time string to be converted. Multiple formats at the same time are also supported using `|` character. The pattern should be designed to match the format of the time strings that will be input to this function. For example:", + examples = Some(Seq( + "'yyyy-MM-dd HH:mm:ss.SSS' for times such as 2024-01-13 22:10:45.167", + "'yyyyMMdd.HH:mm:ss' for times such as 20240113.22:10:45" + )) + ), + FhirPathFunctionParameter( + name = "zoneId", + detail = "The Java ZoneId representation of the time zone to be applied to the date-time string. For example:", + examples = Some(Seq( + "Europe/Berlin", + "America/New_York", + "Asia/Tokyo" + )) + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "\"2024-01-13 22:10:45\"" + ) + ), + examples = Seq( + "'20240113.22:10:45'.utl:toFhirDateTime('yyyy-MM-dd HH:mm:ss', 'Europe/Berlin')" + ) + ), + insertText = "utl:toFhirDateTime(, )", + detail = "utl", + label = "utl:toFhirDateTime", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.DATETIME), + inputType = Seq(FHIR_DATA_TYPES.STRING) + ) def toFhirDateTime(sourcePattern: ExpressionContext, zoneId: ExpressionContext): Seq[FhirPathResult] = { val pattern = new FhirPathExpressionEvaluator(context, current).visit(sourcePattern) if (pattern.isEmpty || !pattern.forall(_.isInstanceOf[FhirPathString])) { @@ -867,8 +1551,36 @@ class FhirPathUtilFunctions(context: FhirPathEnvironment, current: Seq[FhirPathR * @param codingList Expression that evaluates to Seq[FhirPathString] in FHIR token query format [system]|[code] * @return */ - @FhirPathFunction(documentation = "\uD83D\uDCDC For FHIR coding elements, filters the ones that match the given coding list as FHIR code query.\n\n\uD83D\uDCDD _@param_ **`codingList`** \nExpression that evaluates to Seq[FhirPathString] in FHIR token query format [system]|[code]\n\n\uD83D\uDD19 _@return_ \n```\ntrue or false\n```\n\n\uD83D\uDCA1 **E.g.** 'http://loinc.org|12345-6'.utl:isCodingIn(Observation.code.coding)", - insertText = "utl:isCodingIn()", detail = "utl", label = "utl:isCodingIn", kind = "Method", returnType = Seq("boolean"), inputType = Seq()) + @FhirPathFunction( + documentation = FhirPathFunctionDocumentation( + detail = "For FHIR coding elements, filters the ones that match the given coding list as FHIR code query.", + usageWarnings = None, + parameters = Some(Seq( + FhirPathFunctionParameter( + name = "codingList", + detail = "Expression that evaluates to Seq[FhirPathString] in FHIR token query format [system]|[code]", + examples = Some(Seq( + "'http://loinc.org|12345-6' for coding elements that match the code in the given system" + )) + ) + )), + returnValue = FhirPathFunctionReturn( + detail = None, + examples = Seq( + "true or false" + ) + ), + examples = Seq( + "'http://loinc.org|12345-6'.utl:isCodingIn(Observation.code.coding)" + ) + ), + insertText = "utl:isCodingIn()", + detail = "utl", + label = "utl:isCodingIn", + kind = "Method", + returnType = Seq(FHIR_DATA_TYPES.BOOLEAN), + inputType = Seq() + ) def isCodingIn(codingList: ExpressionContext): Seq[FhirPathResult] = { val systemAndCodes: Seq[(Option[String], Option[String])] = new FhirPathExpressionEvaluator(context, current).visit(codingList) match { case s: Seq[_] if s.forall(i => i.isInstanceOf[FhirPathString]) => diff --git a/onfhir-path/src/main/scala/io/onfhir/path/annotation/FhirPathFunction.scala b/onfhir-path/src/main/scala/io/onfhir/path/annotation/FhirPathFunction.scala index 2c99f390..7e00b7fd 100644 --- a/onfhir-path/src/main/scala/io/onfhir/path/annotation/FhirPathFunction.scala +++ b/onfhir-path/src/main/scala/io/onfhir/path/annotation/FhirPathFunction.scala @@ -6,7 +6,7 @@ import scala.annotation.StaticAnnotation * Custom annotation to mark a method as FhirPath function. It provides a documentation of the function which can be used * by a code editor to suggest available functions to the user. * - * @param documentation A human-readable string that represents a doc-comment. + * @param documentation Detailed documentation about the function, including parameters, return information, and examples. * @param insertText A string or snippet that should be inserted in a document when selecting this completion. * @param detail The library prefix to which FhirPath function belongs. * @param label The label (i.e. name) of function. @@ -17,7 +17,7 @@ import scala.annotation.StaticAnnotation * @param inputType Possible input types of a method. It could be an empty sequence indicating that it accepts a collection of any data types. * For functions (i.e. the ones whose kind are 'Function'), it should be an empty sequence because they do not need any input collection to run. */ -class FhirPathFunction(val documentation: String, +class FhirPathFunction(val documentation: FhirPathFunctionDocumentation, val insertText: String, val detail: String, val label: String, @@ -25,3 +25,50 @@ class FhirPathFunction(val documentation: String, val returnType: Seq[String], val inputType: Seq[String] ) extends StaticAnnotation + +/** + * Documentation details for a FhirPath function, including parameters, return information, and examples. + * + * To add a JSON as an example, use the following syntax: + * - Wrap your JSON in triple quotation marks with the "json" language identifier for proper formatting: + * """[{"reference":"Observation/123"},{"reference":"Observation/456"}]""" + * - Note: JSON formatting is supported only for parameters and return value examples. tag will not affect other fields. + * + * @param detail A detailed explanation of the function, its behavior, or its purpose. + * @param usageWarnings A collection of warnings or notes regarding the function's usage. These might include + * constraints, edge cases, or common pitfalls to avoid when using the function. + * @param parameters The parameters that the function accepts, each with its own explanation and examples. + * @param returnValue Information about the return type of the function, including its description and examples. + * @param examples Examples illustrating how to use the function in practice. + */ +case class FhirPathFunctionDocumentation( + detail: String, + usageWarnings: Option[Seq[String]], + parameters: Option[Seq[FhirPathFunctionParameter]], + returnValue: FhirPathFunctionReturn, + examples: Seq[String] + ) + +/** + * Parameter information for a FhirPath function. + * + * @param name The name of the parameter. + * @param detail A description of the parameter, explaining its purpose and how it is used. + * @param examples Examples illustrating valid values or usage for the parameter. + */ +case class FhirPathFunctionParameter( + name: String, + detail: String, + examples: Option[Seq[String]] + ) + +/** + * Information about the return type of a FhirPath function. + * + * @param detail A description of the return value, explaining what the function returns. + * @param examples Examples illustrating the structure or content of the return value. + */ +case class FhirPathFunctionReturn( + detail: Option[String], + examples: Seq[String] + ) \ No newline at end of file