chore: Modify logic to detect and hide deep paths in autocomplete suggestions (#33966)

## Description
This PR modifies how the AutocompleteSortRules suppresses paths with
more than 2 level of nesting.

Example: `Table1.selectedRow.address`
A path like the above should be suppressed from autocomplete suggestion
but it should not suppress `.run` of a module instance with autocomplete
params

Example `QueryModule1.run({ limit: 10, user: appsmith.user.name })`
With the above completion, the AutocompleteSortRules's
NoDeepNestedSuggestionsRule check for the `text` property of the
completion and checked agains the value shared in the above example.
This resulted in suppression of the `QueryModule.run` for the
autocomplete list. Therefore the logic now shift from check the `text`
property which is what gets replaced on selection to `displayText` which
is what we see in the autocomplete suggestion.

Fixes https://github.com/appsmithorg/appsmith/issues/33959

## Automation

/ok-to-test tags="@tag.All"

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/9378147789>
> Commit: 62c4d96c18b2ed931dbe9d671f1eeaaa5c989059
> Cypress dashboard url: <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=9378147789&attempt=3"
target="_blank">Click here!</a>

<!-- end of auto-generated comment: Cypress test results  -->













## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [x] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Enhanced autocomplete functionality by considering `displayText` for
more accurate suggestions.
- Improved code completion in the test suite by adding a new parameter
`name` with a default value referencing `appsmith.user.name`.

- **Tests**
- Updated test cases to reflect new autocomplete and code completion
features, including new declarations for `fieldEntityInformation`.

- **Refactor**
- Updated internal logic to handle new properties and ensure consistency
across the application.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
ashit-rath 2024-06-06 17:38:40 +05:30 committed by GitHub
parent 33b3949445
commit 1e8a962b8b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 56 additions and 19 deletions

View File

@ -32,6 +32,7 @@ export const getShowHintOptions = (
data: {},
text: "",
shortcut: "",
displayText: "",
};
const cursor = editor.getCursor();
return {

View File

@ -130,7 +130,9 @@ class NoDeepNestedSuggestionsRule implements AutocompleteRule {
static threshold = -Infinity;
computeScore(completion: Completion<TernCompletionResult>): number {
let score = 0;
if (completion.text.split(".").length > 2)
const text = completion.displayText || "";
if (text.split(".").length > 2)
score = NoDeepNestedSuggestionsRule.threshold;
return score;
}

View File

@ -26,11 +26,13 @@ const bigDoc = 250;
const cls = "CodeMirror-Tern-";
const hintDelay = 1700;
type MakeRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
export interface Completion<
T = {
doc: string;
},
> extends Hint {
> extends MakeRequired<Hint, "displayText"> {
origin: string;
type: AutocompleteDataType | string;
data: T;

View File

@ -14,6 +14,7 @@ import { AutocompleteSorter, ScoredCompletion } from "../AutocompleteSortRules";
import type CodeMirror from "codemirror";
import type { Def } from "tern";
import type { Doc } from "codemirror";
import type { FieldEntityInformation } from "components/editorComponents/CodeEditor/EditorConfig";
jest.mock("utils/getCodeMirrorNamespace", () => {
const actual = jest.requireActual("utils/getCodeMirrorNamespace");
@ -243,6 +244,7 @@ describe("Tern server sorting", () => {
new Map();
const contextCompletion: Completion = {
text: "context",
displayText: "context",
type: AutocompleteDataType.STRING,
origin: "[doc]",
data: {
@ -252,6 +254,7 @@ describe("Tern server sorting", () => {
const sameEntityCompletion: Completion<any> = {
text: "sameEntity.tableData",
displayText: "sameEntity.tableData",
type: AutocompleteDataType.ARRAY,
origin: "DATA_TREE",
data: {},
@ -267,6 +270,7 @@ describe("Tern server sorting", () => {
const priorityCompletion: Completion<any> = {
text: "selectedRow",
displayText: "selectedRow",
type: AutocompleteDataType.OBJECT,
origin: "DATA_TREE",
data: {},
@ -282,6 +286,7 @@ describe("Tern server sorting", () => {
const diffTypeCompletion: Completion<any> = {
text: "diffType.tableData",
displayText: "diffType.tableData",
type: AutocompleteDataType.ARRAY,
origin: "DATA_TREE.WIDGET",
data: {},
@ -298,6 +303,7 @@ describe("Tern server sorting", () => {
const sameTypeDiffEntityTypeCompletion: Completion<any> = {
text: "diffEntity.data",
displayText: "diffEntity.data",
type: AutocompleteDataType.OBJECT,
origin: "DATA_TREE",
data: {},
@ -310,6 +316,7 @@ describe("Tern server sorting", () => {
const dataTreeCompletion: Completion<any> = {
text: "otherDataTree",
displayText: "otherDataTree",
type: AutocompleteDataType.STRING,
origin: "DATA_TREE",
data: {},
@ -322,6 +329,7 @@ describe("Tern server sorting", () => {
const functionCompletion: Completion<any> = {
text: "otherDataFunction",
displayText: "otherDataFunction",
type: AutocompleteDataType.FUNCTION,
origin: "DATA_TREE.APPSMITH.FUNCTIONS",
data: {},
@ -329,6 +337,7 @@ describe("Tern server sorting", () => {
const ecmascriptCompletion: Completion<any> = {
text: "otherJS",
displayText: "otherJS",
type: AutocompleteDataType.OBJECT,
origin: "ecmascript",
data: {},
@ -336,6 +345,7 @@ describe("Tern server sorting", () => {
const libCompletion: Completion<any> = {
text: "libValue",
displayText: "libValue",
type: AutocompleteDataType.OBJECT,
origin: "LIB/lodash",
data: {},
@ -343,6 +353,7 @@ describe("Tern server sorting", () => {
const unknownCompletion: Completion<any> = {
text: "unknownSuggestion",
displayText: "unknownSuggestion",
type: AutocompleteDataType.UNKNOWN,
origin: "unknown",
data: {},
@ -445,8 +456,10 @@ describe("Tern server completion", () => {
"!type": "?",
},
run: {
"!type": "fn(inputs: {gender: any, limit: any}) -> +Promise",
"!fnParams": '{ gender: "male", limit: "5" }',
"!type":
"fn(inputs: {gender: any, limit: any, name: any }) -> +Promise",
"!fnParams":
'{ gender: "male", limit: "5", name: "Mr. " + appsmith.user.name }',
"!url":
"https://docs.appsmith.com/reference/appsmith-framework/query-object#queryrun",
"!doc": "Executes the query with the given input values.",
@ -461,7 +474,8 @@ describe("Tern server completion", () => {
},
"QueryModule11.run": {
"!type": "fn(inputs: {gender: any, limit: any}) -> +Promise",
"!fnParams": '{ gender: "male", limit: "5" }',
"!fnParams":
'{ gender: "male", limit: "5", name: "Mr. " + appsmith.user.name }',
"!url":
"https://docs.appsmith.com/reference/appsmith-framework/query-object#queryrun",
"!doc": "Executes the query with the given input values.",
@ -496,7 +510,7 @@ describe("Tern server completion", () => {
},
{
name: "QueryModule11.run",
type: "fn(inputs: {gender: ?, limit: ?}) -> Promise",
type: "fn(inputs: {gender: ?, limit: ?, name: ?}) -> Promise",
doc: "Executes the query with the given input values.",
url: "https://docs.appsmith.com/reference/appsmith-framework/query-object#queryrun",
origin: "DATA_TREE",
@ -542,12 +556,12 @@ describe("Tern server completion", () => {
isEntityName: true,
},
{
text: 'QueryModule11.run({ gender: "male", limit: "5" })',
text: 'QueryModule11.run({ gender: "male", limit: "5", name: "Mr. " + appsmith.user.name })',
displayText: "QueryModule11.run",
className: "CodeMirror-Tern-completion CodeMirror-Tern-completion-fn",
data: {
name: "QueryModule11.run",
type: "fn(inputs: {gender: ?, limit: ?}) -> Promise",
type: "fn(inputs: {gender: ?, limit: ?, name: ?}) -> Promise",
doc: "Executes the query with the given input values.",
url: "https://docs.appsmith.com/reference/appsmith-framework/query-object#queryrun",
origin: "DATA_TREE",
@ -560,13 +574,7 @@ describe("Tern server completion", () => {
},
];
// The current cursor location that is being written in the code mirror editor
MockCodemirrorEditor.getCursor.mockResolvedValue({
line: 10,
ch: 30,
sticky: null,
});
MockCodemirrorEditor.getTokenAt.mockResolvedValue({
const mockToken = {
start: 22,
end: 30,
string: "QueryMod",
@ -639,8 +647,35 @@ describe("Tern server completion", () => {
},
indented: 4,
},
});
};
const fieldEntityInformation = {
mode: "javascript",
isTriggerPath: true,
entityName: "JSObject1",
propertyPath: "body",
entityType: "JSACTION",
blockCompletions: [
{
parentPath: "this",
subPath: "myFun2()",
},
{
parentPath: "JSObject1",
subPath: "myFun2()",
},
],
token: mockToken,
} as FieldEntityInformation;
// The current cursor location that is being written in the code mirror editor
MockCodemirrorEditor.getCursor.mockResolvedValue({
line: 10,
ch: 30,
sticky: null,
});
MockCodemirrorEditor.getTokenAt.mockResolvedValue(mockToken);
CodemirrorTernService.fieldEntityInformation = fieldEntityInformation;
CodemirrorTernService.entityDef = entityDef;
// The current line that is being written in the code mirror editor
@ -662,9 +697,6 @@ describe("Tern server completion", () => {
name: "",
changed: null,
});
jest
.spyOn(AutocompleteSorter, "sort")
.mockImplementation((completions) => completions);
CodemirrorTernService.defEntityInformation = new Map([
[