You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2026/09/21 11:21:02 UTC

(camel) branch fix/CAMEL-24874 created (now d18ec2cd50a1)

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a change to branch fix/CAMEL-24874
in repository https://gitbox.apache.org/repos/asf/camel.git


      at d18ec2cd50a1 CAMEL-24874: camel-core-languages - the simple init block operators := and ~:= are in the catalog

This branch includes the following new commits:

     new d18ec2cd50a1 CAMEL-24874: camel-core-languages - the simple init block operators := and ~:= are in the catalog

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(camel) 01/01: CAMEL-24874: camel-core-languages - the simple init block operators := and ~:= are in the catalog

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch fix/CAMEL-24874
in repository https://gitbox.apache.org/repos/asf/camel.git

commit d18ec2cd50a143bd4181b83af5c0786c90790dc8
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Sep 21 13:20:49 2026 +0200

    CAMEL-24874: camel-core-languages - the simple init block operators := and ~:= are in the catalog
    
    The init block of a simple expression ($init{ ... }init$) assigns local
    variables with := and declares local custom functions with ~:= (usually a
    ~> chain), but the catalog had no operator entry for either, so nothing
    that reads simple.json knew they existed: camel_catalog_doc / tui_catalog_doc
    (operator syntax list and optionsFilter), the generated JS validator, the
    MCP server and any agent fetching the catalog. The docs were the only
    source, and docPage=advanced is the whole simple-advanced page.
    
    Both operators are declared in SimpleOperatorConstants (kind init) with
    their syntax and complete examples, listed in the operators doc table with
    a link to the init block sections, and the unfinished sentence and typos
    of the "Init Blocks with custom functions" section are fixed.
    
    Co-Authored-By: Claude Opus 5 (1M context) <no...@anthropic.com>
    Signed-off-by: Claus Ibsen <cl...@gmail.com>
---
 .../apache/camel/catalog/docs/simple-advanced.adoc   |  4 +---
 .../apache/camel/catalog/docs/simple-operators.adoc  |  2 ++
 .../org/apache/camel/catalog/languages/simple.json   |  4 +++-
 .../camel/catalog/simple/camel-simple-validator.js   |  4 +++-
 .../org/apache/camel/language/simple/simple.json     |  4 +++-
 .../modules/languages/pages/simple-advanced.adoc     |  4 +---
 .../modules/languages/pages/simple-operators.adoc    |  2 ++
 .../language/simple/SimpleOperatorConstants.java     | 20 ++++++++++++++++++++
 .../dsl/jbang/core/commands/ai/CatalogDocsTest.java  | 15 +++++++++++++++
 9 files changed, 50 insertions(+), 9 deletions(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/simple-advanced.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/simple-advanced.adoc
index 58c5c2057aed..8925f33c254f 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/simple-advanced.adoc
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/simple-advanced.adoc
@@ -160,9 +160,7 @@ and then refer to the file such as `resource:classpath:mymapping.txt` where the
 
 === Init Blocks with custom functions
 
-You can also declare custom functions using
-
-Inside the init block, it is a lso possible to define custom functions in the syntax `$nane ~:= <statement>;` where you can then use simple language to declare
+Inside the init block, it is also possible to define custom functions in the syntax `$name ~:= <statement>;` where you can then use simple language to declare
 the structure of the function. Then you can later use these custom functions in your simple language expressions.
 
 For example to create a function that can cleanup a `String` value:
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/simple-operators.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/simple-operators.adoc
index da22008cd82e..e5354e79f7db 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/simple-operators.adoc
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/simple-operators.adoc
@@ -115,6 +115,8 @@ The following other operators can be used:
 |`?:` | The elvis operator returns the left-hand side if it has an effective Boolean value of true, otherwise it returns the right-hand side. This is useful for providing fallback values when an expression may evaluate to a value with an effective Boolean value of false (such as `null`, `false`, `0`, empty/blank string).
 |`~>` | The chain operator is used in the situations where multiple nested functions need to be applied to a value, while making it easy to read. The value on the left-hand-side is evaluated, and set as the new message body before evaluating the right-hand-side function. This concept is similar to the xref:eips:pipeline-eip.adoc[Pipeline EIP].
 |`?~>` | The null-safe chain operator, where the chain will not continue when a function returned `null`.
+|`:=` | Assigns a local variable in the init block at the top of an expression (`$init{ $minAge := 18; }init$`), see xref:simple-advanced.adoc#_init_blocks[Init Blocks].
+|`~:=` | Declares a local custom function in the init block, usually as a chain (`$init{ $clean ~:= ${trim()} ~> ${uppercase()}; }init$`), called as `${clean()}`, see xref:simple-advanced.adoc#_init_blocks_with_custom_functions[Init Blocks with custom functions].
 |====
 
 ==== Ternary Operator
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
index 4e7580acfd4e..e2b8a01cf9be 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
@@ -213,6 +213,8 @@
     "? :": { "index": 30, "kind": "operator", "displayName": "Ternary", "label": "ternary", "required": false, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Ternary conditional operator. Evaluates the predicate and returns trueValue if true, falseValue if false. Requires spaces around both ? and : tokens.", "operatorKind": "ternary", "operatorSyntax": "predicate ? trueValue : falseValue", "precedence": 25, "examples": [ "${header.foo} >  [...]
     "~>": { "index": 31, "kind": "operator", "displayName": "Chain", "label": "chain", "required": false, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Pipes the result of the left expression as input body to the right expression. Use $param in the right expression to reference the piped value explicitly.", "operatorKind": "chain", "operatorSyntax": "expr ~> expr", "precedence": 5, "examples": [ "${trim()} ~> ${uppercase()}", "${substrin [...]
     "?~>": { "index": 32, "kind": "operator", "displayName": "Chain null safe", "label": "chain", "required": false, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Null-safe chain operator. Same as ~> but stops chaining and returns null if the left expression evaluates to null.", "operatorKind": "chain", "operatorSyntax": "expr ?~> expr", "precedence": 5, "examples": [ "${header.name} ?~> ${trim()} ?~> ${uppercase()}" ] },
-    "?:": { "index": 33, "kind": "operator", "displayName": "Elvis", "label": "other", "required": false, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Elvis operator (null-coalescing). Returns the left operand if it is not null\/empty, otherwise returns the right operand as a fallback value.", "operatorKind": "other", "operatorSyntax": "expr ?: defaultValue", "precedence": 20, "examples": [ "${header.username} ?: 'Guest'", "${body} ?: $ [...]
+    "?:": { "index": 33, "kind": "operator", "displayName": "Elvis", "label": "other", "required": false, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Elvis operator (null-coalescing). Returns the left operand if it is not null\/empty, otherwise returns the right operand as a fallback value.", "operatorKind": "other", "operatorSyntax": "expr ?: defaultValue", "precedence": 20, "examples": [ "${header.username} ?: 'Guest'", "${body} ?: $ [...]
+    ":=": { "index": 34, "kind": "operator", "displayName": "Init variable", "label": "init", "required": false, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Assigns a local variable in the init block at the top of an expression ($init{ ... }init$), computed once and used in the expression as ${name}. Each statement ends with a semicolon and a new line.", "operatorKind": "init", "operatorSyntax": "$name := expr;", "precedence": 1, "exam [...]
+    "~:=": { "index": 35, "kind": "operator", "displayName": "Init function", "label": "init", "required": false, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Declares a local custom function in the init block at the top of an expression ($init{ ... }init$), usually as a chain of functions on the input, called as ${name()} (the message body as input), ${name(exp)} (an explicit input) or from another function as ${function(name)}. Each s [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/simple/camel-simple-validator.js b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/simple/camel-simple-validator.js
index fedf540459e7..091e88d267c2 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/simple/camel-simple-validator.js
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/simple/camel-simple-validator.js
@@ -192,7 +192,9 @@ const OPERATORS = {
   '? :': { kind: 'ternary', description: 'Ternary conditional operator. Evaluates the predicate and returns trueValue if true, falseValue if false. Requires spaces around both ? and : tokens.' },
   '~>': { kind: 'chain', description: 'Pipes the result of the left expression as input body to the right expression. Use $param in the right expression to reference the piped value explicitly.' },
   '?~>': { kind: 'chain', description: 'Null-safe chain operator. Same as ~> but stops chaining and returns null if the left expression evaluates to null.' },
-  '?:': { kind: 'other', description: 'Elvis operator (null-coalescing). Returns the left operand if it is not null/empty, otherwise returns the right operand as a fallback value.' }
+  '?:': { kind: 'other', description: 'Elvis operator (null-coalescing). Returns the left operand if it is not null/empty, otherwise returns the right operand as a fallback value.' },
+  ':=': { kind: 'init', description: 'Assigns a local variable in the init block at the top of an expression ($init{ ... }init$), computed once and used in the expression as ${name}. Each statement ends with a semicolon and a new line.' },
+  '~:=': { kind: 'init', description: 'Declares a local custom function in the init block at the top of an expression ($init{ ... }init$), usually as a chain of functions on the input, called as ${name()} (the message body as input), ${name(exp)} (an explicit input) or from another function as ${function(name)}. Each statement ends with a semicolon and a new line.' }
 };
 
 
diff --git a/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json b/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
index 4e7580acfd4e..e2b8a01cf9be 100644
--- a/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
+++ b/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
@@ -213,6 +213,8 @@
     "? :": { "index": 30, "kind": "operator", "displayName": "Ternary", "label": "ternary", "required": false, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Ternary conditional operator. Evaluates the predicate and returns trueValue if true, falseValue if false. Requires spaces around both ? and : tokens.", "operatorKind": "ternary", "operatorSyntax": "predicate ? trueValue : falseValue", "precedence": 25, "examples": [ "${header.foo} >  [...]
     "~>": { "index": 31, "kind": "operator", "displayName": "Chain", "label": "chain", "required": false, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Pipes the result of the left expression as input body to the right expression. Use $param in the right expression to reference the piped value explicitly.", "operatorKind": "chain", "operatorSyntax": "expr ~> expr", "precedence": 5, "examples": [ "${trim()} ~> ${uppercase()}", "${substrin [...]
     "?~>": { "index": 32, "kind": "operator", "displayName": "Chain null safe", "label": "chain", "required": false, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Null-safe chain operator. Same as ~> but stops chaining and returns null if the left expression evaluates to null.", "operatorKind": "chain", "operatorSyntax": "expr ?~> expr", "precedence": 5, "examples": [ "${header.name} ?~> ${trim()} ?~> ${uppercase()}" ] },
-    "?:": { "index": 33, "kind": "operator", "displayName": "Elvis", "label": "other", "required": false, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Elvis operator (null-coalescing). Returns the left operand if it is not null\/empty, otherwise returns the right operand as a fallback value.", "operatorKind": "other", "operatorSyntax": "expr ?: defaultValue", "precedence": 20, "examples": [ "${header.username} ?: 'Guest'", "${body} ?: $ [...]
+    "?:": { "index": 33, "kind": "operator", "displayName": "Elvis", "label": "other", "required": false, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Elvis operator (null-coalescing). Returns the left operand if it is not null\/empty, otherwise returns the right operand as a fallback value.", "operatorKind": "other", "operatorSyntax": "expr ?: defaultValue", "precedence": 20, "examples": [ "${header.username} ?: 'Guest'", "${body} ?: $ [...]
+    ":=": { "index": 34, "kind": "operator", "displayName": "Init variable", "label": "init", "required": false, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Assigns a local variable in the init block at the top of an expression ($init{ ... }init$), computed once and used in the expression as ${name}. Each statement ends with a semicolon and a new line.", "operatorKind": "init", "operatorSyntax": "$name := expr;", "precedence": 1, "exam [...]
+    "~:=": { "index": 35, "kind": "operator", "displayName": "Init function", "label": "init", "required": false, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Declares a local custom function in the init block at the top of an expression ($init{ ... }init$), usually as a chain of functions on the input, called as ${name()} (the message body as input), ${name(exp)} (an explicit input) or from another function as ${function(name)}. Each s [...]
   }
 }
diff --git a/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-advanced.adoc b/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-advanced.adoc
index 58c5c2057aed..8925f33c254f 100644
--- a/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-advanced.adoc
+++ b/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-advanced.adoc
@@ -160,9 +160,7 @@ and then refer to the file such as `resource:classpath:mymapping.txt` where the
 
 === Init Blocks with custom functions
 
-You can also declare custom functions using
-
-Inside the init block, it is a lso possible to define custom functions in the syntax `$nane ~:= <statement>;` where you can then use simple language to declare
+Inside the init block, it is also possible to define custom functions in the syntax `$name ~:= <statement>;` where you can then use simple language to declare
 the structure of the function. Then you can later use these custom functions in your simple language expressions.
 
 For example to create a function that can cleanup a `String` value:
diff --git a/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-operators.adoc b/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-operators.adoc
index da22008cd82e..e5354e79f7db 100644
--- a/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-operators.adoc
+++ b/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-operators.adoc
@@ -115,6 +115,8 @@ The following other operators can be used:
 |`?:` | The elvis operator returns the left-hand side if it has an effective Boolean value of true, otherwise it returns the right-hand side. This is useful for providing fallback values when an expression may evaluate to a value with an effective Boolean value of false (such as `null`, `false`, `0`, empty/blank string).
 |`~>` | The chain operator is used in the situations where multiple nested functions need to be applied to a value, while making it easy to read. The value on the left-hand-side is evaluated, and set as the new message body before evaluating the right-hand-side function. This concept is similar to the xref:eips:pipeline-eip.adoc[Pipeline EIP].
 |`?~>` | The null-safe chain operator, where the chain will not continue when a function returned `null`.
+|`:=` | Assigns a local variable in the init block at the top of an expression (`$init{ $minAge := 18; }init$`), see xref:simple-advanced.adoc#_init_blocks[Init Blocks].
+|`~:=` | Declares a local custom function in the init block, usually as a chain (`$init{ $clean ~:= ${trim()} ~> ${uppercase()}; }init$`), called as `${clean()}`, see xref:simple-advanced.adoc#_init_blocks_with_custom_functions[Init Blocks with custom functions].
 |====
 
 ==== Ternary Operator
diff --git a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleOperatorConstants.java b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleOperatorConstants.java
index 658878ea5778..6b1c8318dbf7 100644
--- a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleOperatorConstants.java
+++ b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleOperatorConstants.java
@@ -239,6 +239,26 @@ public final class SimpleOperatorConstants {
               annotations = { "kind=other", "syntax=expr ?: defaultValue", "precedence=20" })
     public static final String ELVIS = "?:";
 
+    // --- Init block operators (only inside $init{ ... }init$ at the start of an expression) ---
+
+    @Metadata(description = "Assigns a local variable in the init block at the top of an expression ($init{ ... }init$),"
+                            + " computed once and used in the expression as ${name}. Each statement ends with a semicolon and a new line.",
+              label = "init",
+              examples = { "$init{\n  $minAge := 18;\n  $greeting := 'Hello ${body}';\n}init$\n${greeting} (${minAge})" },
+              annotations = { "kind=init", "syntax=$name := expr;", "precedence=1" })
+    public static final String INIT_VARIABLE = ":=";
+
+    @Metadata(description = "Declares a local custom function in the init block at the top of an expression ($init{ ... }init$),"
+                            + " usually as a chain of functions on the input, called as ${name()} (the message body as input),"
+                            + " ${name(exp)} (an explicit input) or from another function as ${function(name)}."
+                            + " Each statement ends with a semicolon and a new line.",
+              label = "init",
+              examples = {
+                      "$init{\n  $cleanName ~:= ${trim()} ~> ${normalizeWhitespace()} ~> ${uppercase()};\n}init$\nCustomer: ${cleanName(${header.customerName})}",
+                      "$init{\n  $clean ~:= ${trim()} ~> ${normalizeWhitespace()};\n  $count ~:= ${clean()} ~> ${split(' ')} ~> ${size()};\n}init$\nYou said: ${clean()} in ${count()} words" },
+              annotations = { "kind=init", "syntax=$name ~:= expr ~> expr;", "precedence=1" })
+    public static final String INIT_FUNCTION = "~:=";
+
     private SimpleOperatorConstants() {
     }
 }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java
index 97cbf8277fbe..a715af758295 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java
@@ -177,6 +177,21 @@ class CatalogDocsTest {
         assertTrue(binary.getInteger("matchedOperators") > 5);
         JsonObject eq = (JsonObject) binary.getCollection("operators").iterator().next();
         assertEquals("LHS == RHS", eq.getString("syntax"));
+
+        // CAMEL-24874: the init block operators are in the catalog, so a model asking about a local function or the
+        // init block gets the syntax and a complete example instead of the whole advanced page
+        JsonObject init = catalogDoc(Map.of("name", "simple", "kind", "language", "optionsFilter", "init"));
+        assertEquals("init", init.getString("operatorKind"));
+        assertEquals(2, init.getInteger("matchedOperators"));
+        JsonObject function = init.getCollection("operators").stream()
+                .map(JsonObject.class::cast)
+                .filter(op -> "~:=".equals(op.getString("name")))
+                .findFirst().orElseThrow();
+        assertEquals("$name ~:= expr ~> expr;", function.getString("syntax"));
+        String example = (String) function.getCollection("examples").iterator().next();
+        assertTrue(example.startsWith("$init{\n") && example.contains("}init$\n"), example);
+        JsonObject summary = catalogDoc(Map.of("name", "simple", "kind", "language"));
+        assertTrue(summary.getCollection("operatorSyntax").contains("$name := expr;"));
     }
 
     @Test