PromucFlow_constructor/app/client/packages/ast/src/peekOverlay/utils.ts
Ilia d6f249b42d
chore: add blank line eslint rule (#36369)
## Description
Added ESLint rule to force blank lines between statements. 


Fixes #`Issue Number`  
_or_  
Fixes `Issue URL`
> [!WARNING]  
> _If no issue exists, please create an issue first, and check with the
maintainers if the issue is valid._

## Automation

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

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!CAUTION]
> 🔴 🔴 🔴 Some tests have failed.
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/10924926728>
> Commit: 34f57714a1575ee04e94e03cbcaf95e57a96c86c
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=10924926728&attempt=1&selectiontype=test&testsstatus=failed&specsstatus=fail"
target="_blank">Cypress dashboard</a>.
> Tags: @tag.All
> Spec: 
> The following are new failures, please fix them before merging the PR:
<ol>
> <li>cypress/e2e/Regression/ClientSide/Anvil/AnvilModal_spec.ts
>
<li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts
>
<li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts
>
<li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts
>
<li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts
>
<li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts
>
<li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts
>
<li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts
>
<li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts
>
<li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts
>
<li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts
>
<li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts
>
<li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts
>
<li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts
>
<li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilZoneSectionWidgetSnapshot_spec.ts</ol>
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/identified-flaky-tests-65890b3c81d7400d08fa9ee3?branch=master"
target="_blank">List of identified flaky tests</a>.
> <hr>Wed, 18 Sep 2024 16:33:36 UTC
<!-- end of auto-generated comment: Cypress test results  -->


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

---------

Co-authored-by: Valera Melnikov <valera@appsmith.com>
2024-09-18 19:35:28 +03:00

201 lines
5.8 KiB
TypeScript

import type { Node } from "acorn";
import type {
BinaryExpressionNode,
CallExpressionNode,
ConditionalExpressionNode,
ExpressionStatement,
IdentifierNode,
MemberExpressionNode,
} from "../index";
import { isAwaitExpressionNode } from "../index";
import { isBinaryExpressionNode } from "../index";
import { isConditionalExpressionNode } from "../index";
import {
isCallExpressionNode,
isExpressionStatementNode,
isIdentifierNode,
isMemberExpressionNode,
isThisExpressionNode,
} from "../index";
import * as escodegen from "escodegen";
import { NodeTypes } from "../constants/ast";
import type { PeekOverlayExpressionIdentifierOptions } from "./index";
export const isPositionWithinNode = (node: Node, pos: number) =>
pos >= node.start && pos <= node.end;
export const getExpressionStringAtPos = (
node: Node,
pos: number,
options?: PeekOverlayExpressionIdentifierOptions,
replaceThisExpression = true,
): string | undefined => {
if (!isPositionWithinNode(node, pos)) return;
if (isMemberExpressionNode(node)) {
return getExpressionAtPosFromMemberExpression(
node,
pos,
options,
replaceThisExpression,
);
} else if (isExpressionStatementNode(node)) {
return getExpressionAtPosFromExpressionStatement(node, pos, options);
} else if (isCallExpressionNode(node)) {
return getExpressionAtPosFromCallExpression(node, pos, options);
} else if (isBinaryExpressionNode(node)) {
return getExpressionAtPosFromBinaryExpression(node, pos, options);
} else if (isAwaitExpressionNode(node)) {
return getExpressionStringAtPos(node.argument, pos, options);
} else if (isConditionalExpressionNode(node)) {
return getExpressionAtPosFromConditionalExpression(node, pos, options);
} else if (isIdentifierNode(node)) {
return removeSemiColon(escodegen.generate(node));
}
};
const getExpressionAtPosFromMemberExpression = (
node: MemberExpressionNode,
pos: number,
options?: PeekOverlayExpressionIdentifierOptions,
replaceThisExpression = true,
): string | undefined => {
const objectNode = node.object;
if (isLocalVariableNode(node) || isLocalVariableNode(objectNode)) return;
if (replaceThisExpression && options?.thisExpressionReplacement) {
node = replaceThisinMemberExpression(node, options);
}
// stop if objectNode is a function call -> needs evaluation
if (isCallExpressionNode(objectNode)) return;
// position is within the object node
if (pos <= objectNode.end) {
return getExpressionStringAtPos(objectNode, pos, options, false);
}
// position is within the property node
else {
const propertyNode = node.property;
if (isMemberExpressionNode(propertyNode)) {
return getExpressionAtPosFromMemberExpression(
propertyNode,
pos,
options,
false,
);
}
// generate string for the whole path
return escodegen.generate(node);
}
};
const getExpressionAtPosFromExpressionStatement = (
node: ExpressionStatement,
pos: number,
options?: PeekOverlayExpressionIdentifierOptions,
): string | undefined => {
if (
isThisExpressionNode(node.expression) &&
options?.thisExpressionReplacement
) {
node.expression = thisReplacementNode(node.expression, options);
}
return getExpressionStringAtPos(node.expression, pos, options);
};
const getExpressionAtPosFromCallExpression = (
node: CallExpressionNode,
pos: number,
options?: PeekOverlayExpressionIdentifierOptions,
): string | undefined => {
let selectedNode: Node | undefined;
// function call -> needs evaluation
// if (isPositionWithinNode(node.callee, pos)) {
// selectedNode = node.callee;
// }
if (node.arguments.length > 0) {
const argumentNode = node.arguments.find((node) =>
isPositionWithinNode(node, pos),
);
if (argumentNode) {
selectedNode = argumentNode;
}
}
return selectedNode && getExpressionStringAtPos(selectedNode, pos, options);
};
const getExpressionAtPosFromConditionalExpression = (
node: ConditionalExpressionNode,
pos: number,
options?: PeekOverlayExpressionIdentifierOptions,
): string | undefined => {
let selectedNode: Node | undefined;
if (isPositionWithinNode(node.test, pos)) {
selectedNode = node.test;
} else if (isPositionWithinNode(node.consequent, pos)) {
selectedNode = node.consequent;
} else if (isPositionWithinNode(node.alternate, pos)) {
selectedNode = node.alternate;
}
return selectedNode && getExpressionStringAtPos(selectedNode, pos, options);
};
const getExpressionAtPosFromBinaryExpression = (
node: BinaryExpressionNode,
pos: number,
options?: PeekOverlayExpressionIdentifierOptions,
): string | undefined => {
let selectedNode: Node | undefined;
if (isPositionWithinNode(node.left, pos)) {
selectedNode = node.left;
} else if (isPositionWithinNode(node.right, pos)) {
selectedNode = node.right;
}
return selectedNode && getExpressionStringAtPos(selectedNode, pos, options);
};
export const replaceThisinMemberExpression = (
node: MemberExpressionNode,
options: PeekOverlayExpressionIdentifierOptions,
): MemberExpressionNode => {
if (isMemberExpressionNode(node.object)) {
node.object = replaceThisinMemberExpression(node.object, options);
} else if (isThisExpressionNode(node.object)) {
node.object = thisReplacementNode(node.object, options);
}
return node;
};
// replace "this" node with the provided replacement
const thisReplacementNode = (
node: Node,
options: PeekOverlayExpressionIdentifierOptions,
) => {
return {
...node,
type: NodeTypes.Identifier,
name: options.thisExpressionReplacement,
} as IdentifierNode;
};
const removeSemiColon = (value: string) =>
value.slice(-1) === ";" ? value.slice(0, value.length - 1) : value;
const isLocalVariableNode = (node: Node) =>
isMemberExpressionNode(node) &&
node.computed &&
isIdentifierNode(node.property);