PromucFlow_constructor/app/client/src/plugins/Linting/constants.ts
ashit-rath 33718b3730
chore: add new custom linter for module inputs (#33940)
## Description
This PR adds a new custom lint function for module inputs. The primary
logic for linting would be present in the EE counterpart. This PR makes
sure the right parameter is passed to the right function and the linter
function is appropriately split for EE

It also a generic `CustomLintErrorCode` called `INVALID_INPUTS`; this is
made generic as there is a possibility of introducing inputs to normal
query and hence this can be reused. If that doesn't happen, it still
should be fine as inputs would only be a concept reserved to module.

PR for https://github.com/appsmithorg/appsmith-ee/pull/4339

## 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/9382849520>
> Commit: 18260e82e9816daf4e6be49a83c0fb08dfc491a4
> Cypress dashboard url: <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=9382849520&attempt=2"
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
- [ ] No


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

- **New Features**
- Improved error handling for invalid module inputs with detailed error
messages.

- **Enhancements**
- Enhanced linting functionality by adding checks for invalid module
inputs.

- **Bug Fixes**
- Fixed inconsistencies in error message generation for invalid inputs.

- **Refactor**
- Renamed and updated parameter types for improved code clarity and
maintainability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2024-06-05 21:09:12 +05:30

133 lines
5.4 KiB
TypeScript

import { ECMA_VERSION } from "@shared/ast";
import type { LintOptions } from "jshint";
import isEntityFunction from "./utils/isEntityFunction";
export const lintOptions = (globalData: Record<string, boolean>) =>
({
indent: 2,
esversion: ECMA_VERSION,
eqeqeq: false, // Not necessary to use ===
curly: false, // Blocks can be added without {}, eg if (x) return true
freeze: true, // Overriding inbuilt classes like Array is not allowed
undef: true, // Undefined variables should be reported as error
forin: false, // Doesn't require filtering for..in loops with obj.hasOwnProperty()
noempty: false, // Empty blocks are allowed
strict: false, // We won't force strict mode
unused: "strict", // Unused variables are not allowed
asi: true, // Tolerate Automatic Semicolon Insertion (no semicolons)
boss: true, // Tolerate assignments where comparisons would be expected
evil: false, // Use of eval not allowed
funcscope: true, // Tolerate variable definition inside control statements
sub: true, // Don't force dot notation
expr: true, // suppresses warnings about the use of expressions where normally you would expect to see assignments or function calls
// environments
browser: false,
worker: true,
mocha: false,
// global values
globals: globalData,
loopfunc: true,
}) as LintOptions;
export const JS_OBJECT_START_STATEMENT = "export default";
export const INVALID_JSOBJECT_START_STATEMENT = `JSObject must start with '${JS_OBJECT_START_STATEMENT}'`;
export const INVALID_JSOBJECT_START_STATEMENT_ERROR_CODE =
"INVALID_JSOBJECT_START_STATEMENT_ERROR_CODE";
// https://github.com/jshint/jshint/blob/d3d84ae1695359aef077ddb143f4be98001343b4/src/messages.js#L204
export const IDENTIFIER_NOT_DEFINED_LINT_ERROR_CODE = "W117";
// For these error types, we want to show a warning
// All messages can be found here => https://github.com/jshint/jshint/blob/2.9.5/src/messages.js
export const WARNING_LINT_ERRORS = {
W098: "'{a}' is defined but never used.",
W014: "Misleading line break before '{a}'; readers may interpret this as an expression boundary.",
ASYNC_FUNCTION_BOUND_TO_SYNC_FIELD:
"Cannot execute async code on functions bound to data fields",
ACTION_MODAL_STRING: 'Use Modal1.name instead of "Modal" as a string',
};
export function asyncActionInSyncFieldLintMessage(isJsObject = false) {
return isJsObject
? `Cannot execute async code on functions bound to data fields`
: `Data fields cannot execute async code`;
}
/** These errors should be overlooked
* E041 => Unrecoverable syntax error.
* W032 => Unnecessary semicolon.
*/
export const IGNORED_LINT_ERRORS = ["E041", "W032"];
export const SUPPORTED_WEB_APIS = {
console: true,
crypto: true,
fetch: true,
};
export enum CustomLintErrorCode {
INVALID_ENTITY_PROPERTY = "INVALID_ENTITY_PROPERTY",
ASYNC_FUNCTION_BOUND_TO_SYNC_FIELD = "ASYNC_FUNCTION_BOUND_TO_SYNC_FIELD",
// ButtonWidget.text = "test"
INVALID_WIDGET_PROPERTY_SETTER = "INVALID_WIDGET_PROPERTY_SETTER",
// appsmith.store.value = "test"
INVALID_APPSMITH_STORE_PROPERTY_SETTER = "INVALID_APPSMITH_STORE_PROPERTY_SETTER",
// showModal("Modal1")
ACTION_MODAL_STRING = "ACTION_MODAL_STRING",
INVALID_INPUTS = "INVALID_INPUTS",
}
export const CUSTOM_LINT_ERRORS: Record<
CustomLintErrorCode,
(...args: any[]) => string
> = {
[CustomLintErrorCode.INVALID_ENTITY_PROPERTY]: (
entityName: string,
propertyName: string,
entity: unknown,
isJsObject: boolean,
) =>
isEntityFunction(entity, propertyName, entityName)
? asyncActionInSyncFieldLintMessage(isJsObject)
: `"${propertyName}" doesn't exist in ${entityName}`,
[CustomLintErrorCode.ASYNC_FUNCTION_BOUND_TO_SYNC_FIELD]: (
dataFieldBindings: string[],
fullName: string,
isMarkedAsync: boolean,
) => {
const hasMultipleBindings = dataFieldBindings.length > 1;
const bindings = dataFieldBindings.join(" , ");
return isMarkedAsync
? `Cannot bind async functions to data fields. Convert this to a sync function or remove references to "${fullName}" on the following data ${
hasMultipleBindings ? "fields" : "field"
}: ${bindings}`
: `Functions bound to data fields cannot execute async code. Remove async statements highlighted below or remove references to "${fullName}" on the following data ${
hasMultipleBindings ? "fields" : "field"
}: ${bindings}`;
},
[CustomLintErrorCode.INVALID_WIDGET_PROPERTY_SETTER]: (
methodName: string,
objectName: string,
propertyName: string,
isValidProperty: boolean,
) => {
const suggestionSentence = methodName
? `Use ${methodName}(value) instead.`
: `Use ${objectName} setter method instead.`;
const lintErrorMessage = !isValidProperty
? `${objectName} doesn't have a property named ${propertyName}`
: `Direct mutation of widget properties is not supported. ${suggestionSentence}`;
return lintErrorMessage;
},
[CustomLintErrorCode.INVALID_APPSMITH_STORE_PROPERTY_SETTER]: () => {
return "Use storeValue() method to modify the store";
},
[CustomLintErrorCode.ACTION_MODAL_STRING]: (modalName: string) => {
return `Use ${modalName}.name instead of "${modalName}" as a string`;
},
[CustomLintErrorCode.INVALID_INPUTS]: (
inputs: string[],
invalidKey: string,
) => {
return `${invalidKey} doesn't exist in valid list of inputs: ${inputs.join(", ")} `;
},
};