You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kie.apache.org by ti...@apache.org on 2024/05/16 13:48:56 UTC

(incubator-kie-tools) branch main updated: kie-issues#1185: In the Filter expression the reserved Item variable should only be available in the last row (#2334)

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

tiagobento pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git


The following commit(s) were added to refs/heads/main by this push:
     new 481e9a64d25 kie-issues#1185: In the Filter expression the reserved Item variable should only be available in the last row (#2334)
481e9a64d25 is described below

commit 481e9a64d251e174714e565b877dae2167e3d1c7
Author: Daniel José dos Santos <da...@users.noreply.github.com>
AuthorDate: Thu May 16 10:48:51 2024 -0300

    kie-issues#1185: In the Filter expression the reserved Item variable should only be available in the last row (#2334)
---
 .../src/parser/FeelSyntacticSymbolNature.ts        |  6 ++
 .../src/parser/FeelVariablesParser.ts              | 12 +++-
 .../src/parser/VariablesRepository.ts              | 11 ++--
 packages/feel-input-component/src/FeelInput.tsx    | 66 +++++++++++++++++++---
 4 files changed, 77 insertions(+), 18 deletions(-)

diff --git a/packages/dmn-feel-antlr4-parser/src/parser/FeelSyntacticSymbolNature.ts b/packages/dmn-feel-antlr4-parser/src/parser/FeelSyntacticSymbolNature.ts
index 108b5443484..3ff35d3177e 100644
--- a/packages/dmn-feel-antlr4-parser/src/parser/FeelSyntacticSymbolNature.ts
+++ b/packages/dmn-feel-antlr4-parser/src/parser/FeelSyntacticSymbolNature.ts
@@ -47,4 +47,10 @@ export enum FeelSyntacticSymbolNature {
    * Variables which the parser currently doesn't know if it is valid or not because they are validated at runtime.
    */
   DynamicVariable,
+
+  /**
+   * Invisible variables are variables used only for the tree structure purpose of the VariablesRepository
+   * and are not available to the user.
+   */
+  InvisibleVariables,
 }
diff --git a/packages/dmn-feel-antlr4-parser/src/parser/FeelVariablesParser.ts b/packages/dmn-feel-antlr4-parser/src/parser/FeelVariablesParser.ts
index 78956e65279..7fc3ff11997 100644
--- a/packages/dmn-feel-antlr4-parser/src/parser/FeelVariablesParser.ts
+++ b/packages/dmn-feel-antlr4-parser/src/parser/FeelVariablesParser.ts
@@ -27,6 +27,7 @@ import { FeelVariable } from "./FeelVariable";
 import { MapBackedType } from "./grammar/MapBackedType";
 import { VariableContext } from "./VariableContext";
 import { ParsedExpression } from "./ParsedExpression";
+import { FeelSyntacticSymbolNature } from "./FeelSyntacticSymbolNature";
 
 export class FeelVariablesParser {
   private variablesRepository: VariablesRepository;
@@ -121,13 +122,18 @@ export class FeelVariablesParser {
     for (const inputVariableId of inputVariables) {
       const inputVariable = this.variablesRepository.variables.get(inputVariableId);
       if (inputVariable) {
-        this.addToParser(parser, inputVariable);
+        this.addToParser(parser, inputVariable, true);
       }
     }
   }
 
-  private addToParser(parser: FEEL_1_1Parser, context: VariableContext) {
-    if (context.variable.value !== "") {
+  private addToParser(parser: FEEL_1_1Parser, context: VariableContext, addInvisibleVariables?: boolean) {
+    if (
+      context.variable.value !== "" &&
+      ((!addInvisibleVariables &&
+        context.variable.feelSyntacticSymbolNature != FeelSyntacticSymbolNature.InvisibleVariables) ||
+        addInvisibleVariables)
+    ) {
       parser.helper.defineVariable(
         context.variable.value,
         context.variable.typeRef ? this.createType(context.variable.typeRef) : undefined,
diff --git a/packages/dmn-feel-antlr4-parser/src/parser/VariablesRepository.ts b/packages/dmn-feel-antlr4-parser/src/parser/VariablesRepository.ts
index c34686d3c64..421834fa89a 100644
--- a/packages/dmn-feel-antlr4-parser/src/parser/VariablesRepository.ts
+++ b/packages/dmn-feel-antlr4-parser/src/parser/VariablesRepository.ts
@@ -258,7 +258,7 @@ export class VariablesRepository {
     const parent = this.addVariable(
       drg["@_id"] ?? "",
       drg["@_name"],
-      FeelSyntacticSymbolNature.GlobalVariable,
+      FeelSyntacticSymbolNature.InvisibleVariables,
       undefined,
       drg.variable?.["@_typeRef"]
     );
@@ -514,7 +514,7 @@ export class VariablesRepository {
     if (expression.in.expression) {
       type = expression.in.expression["@_typeRef"];
     }
-    const localParent = this.addVariable(
+    return this.addVariable(
       expression["@_id"] ?? "",
       "item",
       FeelSyntacticSymbolNature.LocalVariable,
@@ -522,8 +522,6 @@ export class VariablesRepository {
       type,
       true
     );
-
-    return localParent;
   }
 
   private addIteratorVariable(parent: VariableContext, expression: DmnFor | DmnEvery | DmnSome) {
@@ -549,10 +547,11 @@ export class VariablesRepository {
   }
 
   private addFilter(parent: VariableContext, expression: DmnFilter) {
-    const localParent = this.addFilterVariable(parent, expression);
     if (expression.in.expression) {
-      this.addInnerExpression(localParent, expression.in.expression);
+      this.addInnerExpression(parent, expression.in.expression);
     }
+
+    const localParent = this.addFilterVariable(parent, expression);
     if (expression.match.expression) {
       this.addInnerExpression(localParent, expression.match.expression);
     }
diff --git a/packages/feel-input-component/src/FeelInput.tsx b/packages/feel-input-component/src/FeelInput.tsx
index ef75e673fec..9d5bc5e3631 100644
--- a/packages/feel-input-component/src/FeelInput.tsx
+++ b/packages/feel-input-component/src/FeelInput.tsx
@@ -136,6 +136,15 @@ export const FeelInput = React.forwardRef<FeelInputRef, FeelInputProps>(
       return lastValidSymbol;
     }, []);
 
+    const getSymbolAtPosition = useCallback((currentParsedExpression: ParsedExpression, position: number) => {
+      for (const feelVariable of currentParsedExpression.feelVariables) {
+        if (feelVariable.startIndex < position && position <= feelVariable.startIndex + feelVariable.length) {
+          return feelVariable;
+        }
+      }
+      return undefined;
+    }, []);
+
     const getDefaultCompletionItems = useCallback(
       (
         suggestionProvider:
@@ -173,7 +182,7 @@ export const FeelInput = React.forwardRef<FeelInputRef, FeelInputProps>(
 
     const completionItemProvider = useCallback(() => {
       return {
-        triggerCharacters: [" ", EXPRESSION_PROPERTIES_SEPARATOR],
+        triggerCharacters: [EXPRESSION_PROPERTIES_SEPARATOR],
         provideCompletionItems: (model: Monaco.editor.ITextModel, position: Monaco.Position) => {
           const completionItems = getDefaultCompletionItems(suggestionProvider, model, position);
           const variablesSuggestions = new Array<Monaco.languages.CompletionItem>();
@@ -183,11 +192,12 @@ export const FeelInput = React.forwardRef<FeelInputRef, FeelInputProps>(
             const expression = model.getValue();
 
             const currentChar = expression.charAt(pos - 1);
-            if (currentChar === EXPRESSION_PROPERTIES_SEPARATOR) {
+            if (currentChar === EXPRESSION_PROPERTIES_SEPARATOR || currentChar === " ") {
               pos--;
             }
 
             const lastValidSymbol = getLastValidSymbolAtPosition(currentParsedExpression, pos);
+
             if (
               lastValidSymbol &&
               lastValidSymbol.feelSymbolNature !== FeelSyntacticSymbolNature.Unknown &&
@@ -199,16 +209,48 @@ export const FeelInput = React.forwardRef<FeelInputRef, FeelInputProps>(
                   label: scopeSymbol.name,
                   insertText: scopeSymbol.name,
                   detail: scopeSymbol.type,
+                  range: {
+                    startLineNumber: lastValidSymbol.startLine + 1,
+                    endLineNumber: lastValidSymbol.endLine + 1,
+                    startColumn: lastValidSymbol.startIndex + lastValidSymbol.length + 2, // It is +2 because of the . (dot)
+                    endColumn: lastValidSymbol.startIndex + lastValidSymbol.length + 2 + scopeSymbol.name.length,
+                  },
                 } as Monaco.languages.CompletionItem);
               }
             } else {
+              const currentSymbol = getSymbolAtPosition(currentParsedExpression, pos);
               for (const scopeSymbol of currentParsedExpression.availableSymbols) {
-                variablesSuggestions.push({
-                  kind: Monaco.languages.CompletionItemKind.Variable,
-                  label: scopeSymbol.name,
-                  insertText: scopeSymbol.name,
-                  detail: scopeSymbol.type,
-                } as Monaco.languages.CompletionItem);
+                // Consider this scenario:
+                // 1. User typed: Tax In
+                // 2. Available symbols: [Tax Incoming, Tax Input, Tax InSomethingElse, Tax Out, Tax Output]
+                // 3. "Tax In" is an invalid symbol (unrecognized symbol)
+                // In this case, we want to show all symbols that starts with "Tax In"
+                if (currentSymbol && scopeSymbol.name.startsWith(currentSymbol.text)) {
+                  variablesSuggestions.push({
+                    kind: Monaco.languages.CompletionItemKind.Variable,
+                    label: scopeSymbol.name,
+                    insertText: scopeSymbol.name,
+                    detail: scopeSymbol.type,
+                    sortText: "1", // We want the variables to be at top of autocomplete
+                    // We want to replace the current symbol with the available scopeSymbol (Tax Incoming, for example)
+                    // Note: Monaco is NOT zero-indexed. It starts with 1 but FEEL parser is zero indexed,
+                    // that's why were incrementing 1 at each position.
+                    range: {
+                      startLineNumber: currentSymbol.startLine + 1,
+                      endLineNumber: currentSymbol.endLine + 1,
+                      startColumn: currentSymbol.startIndex + 1,
+                      endColumn: currentSymbol.startIndex + 1 + scopeSymbol.name.length,
+                    },
+                  } as Monaco.languages.CompletionItem);
+                } else {
+                  variablesSuggestions.push({
+                    kind: Monaco.languages.CompletionItemKind.Variable,
+                    label: scopeSymbol.name,
+                    insertText: scopeSymbol.name,
+                    detail: scopeSymbol.type,
+                    sortText: "2", // The others variables at second level
+                  } as Monaco.languages.CompletionItem);
+                }
               }
 
               variablesSuggestions.push(...completionItems);
@@ -222,7 +264,13 @@ export const FeelInput = React.forwardRef<FeelInputRef, FeelInputProps>(
           };
         },
       };
-    }, [currentParsedExpression, getDefaultCompletionItems, getLastValidSymbolAtPosition, suggestionProvider]);
+    }, [
+      currentParsedExpression,
+      getDefaultCompletionItems,
+      getLastValidSymbolAtPosition,
+      getSymbolAtPosition,
+      suggestionProvider,
+    ]);
 
     useEffect(() => {
       if (!enabled) {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org