Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: created shared utils package and moved objectKeys function to it #35615

Merged
merged 27 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e3cfc58
chore: created utils package and moved objectKeys function to it
AmanAgarwal041 Aug 12, 2024
5606509
fix: utils packages imports
AmanAgarwal041 Aug 13, 2024
dbb3c9a
fix: jest config
AmanAgarwal041 Aug 13, 2024
dabf5e4
fix: changed to named exports
AmanAgarwal041 Aug 13, 2024
bc86aab
fix: package structure
KelvinOm Aug 13, 2024
2ccacd8
fix: added the eslint custom package to warn the use of Object.keys o…
AmanAgarwal041 Aug 14, 2024
b3f5a41
fix: updated the message
AmanAgarwal041 Aug 14, 2024
d0644b3
fix: updated the require
AmanAgarwal041 Aug 14, 2024
0c821d2
Merge branch 'release' of github.com:appsmithorg/appsmith into chore/…
AmanAgarwal041 Aug 14, 2024
225b6f2
chore: added test case for rule, readme for adding new rule
AmanAgarwal041 Aug 14, 2024
8f982d9
fix: prettier in jest config
AmanAgarwal041 Aug 14, 2024
a4e9315
Merge branch 'release' of github.com:appsmithorg/appsmith into chore/…
AmanAgarwal041 Aug 14, 2024
19d7015
fix: merge from release
AmanAgarwal041 Aug 16, 2024
abe98cb
fix: moved eslint to typescript
AmanAgarwal041 Aug 16, 2024
f26b759
chore: add build script for custom lint rules
KelvinOm Aug 16, 2024
d09df0f
fix: jest config
AmanAgarwal041 Aug 16, 2024
0809b7e
fix: eslint and prettierconfig
AmanAgarwal041 Aug 16, 2024
0407be6
fix: updated the design-sytem package, removed readme from prettier, …
AmanAgarwal041 Aug 16, 2024
3b3a23e
Merge branch 'release' of github.com:appsmithorg/appsmith into chore/…
AmanAgarwal041 Aug 21, 2024
7463e68
fix: removed cypress config change
AmanAgarwal041 Aug 21, 2024
491ccbf
fix: changed the export format
AmanAgarwal041 Aug 21, 2024
cebbf83
fix: changed to module exports
AmanAgarwal041 Aug 21, 2024
75ac33d
Merge branch 'release' of github.com:appsmithorg/appsmith into chore/…
AmanAgarwal041 Aug 21, 2024
fe4709e
fix: removed prettier and updated package json, readme
AmanAgarwal041 Aug 22, 2024
eb5f9fe
fix: updated readme md
AmanAgarwal041 Aug 22, 2024
f9ab8c9
Merge branch 'release' of github.com:appsmithorg/appsmith into chore/…
AmanAgarwal041 Aug 22, 2024
f5e0eef
fix: added prettier for dist
AmanAgarwal041 Aug 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion app/client/.eslintrc.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@
"sort-destructure-keys",
"cypress",
"testing-library",
"jest"
"jest",
"@appsmith"
],
"extends": [
"plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react
"plugin:@typescript-eslint/recommended",
"plugin:cypress/recommended",
"plugin:testing-library/react",
"plugin:react-hooks/recommended",
"plugin:@appsmith/recommended",
// Note: Please keep this as the last config to make sure that this (and by extension our .prettierrc file) overrides all configuration above it
// https://www.npmjs.com/package/eslint-plugin-prettier#recommended-configuration
"plugin:prettier/recommended"
Expand Down
2 changes: 2 additions & 0 deletions app/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"dependencies": {
"@appsmith/ads": "workspace:^",
"@appsmith/ads-old": "workspace:^",
"@appsmith/utils": "workspace:^",
"@appsmith/wds": "workspace:^",
"@appsmith/wds-theming": "workspace:^",
"@aws-sdk/client-s3": "^3.622.0",
Expand Down Expand Up @@ -251,6 +252,7 @@
"not op_mini all"
],
"devDependencies": {
"@appsmith/eslint-plugin": "workspace:^",
"@babel/helper-create-regexp-features-plugin": "^7.18.6",
"@babel/helper-string-parser": "^7.19.4",
"@craco/craco": "^7.0.0",
Expand Down
1 change: 1 addition & 0 deletions app/client/packages/design-system/widgets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"build:icons": "npx tsx ./src/scripts/build-icons.ts"
},
"dependencies": {
"@appsmith/utils": "workspace:^",
"@appsmith/wds-headless": "workspace:^",
"@appsmith/wds-theming": "workspace:^",
"@emotion/css": "^11.11.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { StoryGrid, DataAttrWrapper } from "@design-system/storybook";
import { Button, BUTTON_VARIANTS, COLORS, objectKeys } from "@appsmith/wds";
import { Button, BUTTON_VARIANTS, COLORS } from "@appsmith/wds";
import { objectKeys } from "@appsmith/utils";

const variants = objectKeys(BUTTON_VARIANTS);
const colors = Object.values(COLORS);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import {
Button,
Flex,
BUTTON_VARIANTS,
COLORS,
SIZES,
objectKeys,
} from "@appsmith/wds";
import { Button, Flex, BUTTON_VARIANTS, COLORS, SIZES } from "@appsmith/wds";
import { objectKeys } from "@appsmith/utils";

/**
* A button is a clickable element that is used to trigger an action.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
SIZES,
BUTTON_VARIANTS,
COLORS,
objectKeys,
} from "@appsmith/wds";
import { objectKeys } from "@appsmith/utils";

/**
* Icon Button is a button component that only contains an icon.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import React from "react";
import {
InlineButtons,
Flex,
objectKeys,
BUTTON_VARIANTS,
COLORS,
SIZES,
} from "@appsmith/wds";
import type { Meta, StoryObj } from "@storybook/react";
import { objectKeys } from "@appsmith/utils";
import {
itemList,
longItemList,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import {
BUTTON_VARIANTS,
COLORS,
Flex,
objectKeys,
ToolbarButtons,
SIZES,
} from "@appsmith/wds";
import { objectKeys } from "@appsmith/utils";
import {
itemList,
itemListWithIcons,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export { filterDataProps } from "./filterDataProps";
export { objectKeys } from "./objectKeys";
4 changes: 4 additions & 0 deletions app/client/packages/eslint-plugin/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"ignorePatterns": ["dist/*", "Readme.md"],
"extends": ["../../.eslintrc.base.json"]
}
106 changes: 106 additions & 0 deletions app/client/packages/eslint-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Adding a Custom Rule to Your Appsmith ESLint Plugin

Welcome to the guide for adding a custom rule to your Appsmith ESLint plugin. Follow these steps to create and integrate a new rule into your Appsmith ESLint plugin.

You can create one by following the [official ESLint custom rule](https://eslint.org/docs/latest/extend/custom-rule-tutorial).

## Step 1: Create the Custom Rule File

1. Navigate to your Appsmith ESLint plugin directory i.e. `app/client/packages/eslint-plugin`.
2. Create a new directory for your custom rule in the root of `app/client/packages/eslint-plugin` directory. For example, `custom-rule/rule.js`.

```bash
mkdir custom-rule
touch custom-rule/rule.js
```

3. Open `custom-rule/rule.js` and define your rule. Here's a basic template to get you started:

```js
module.exports = {
meta: {
type: "problem", // or "suggestion" or "layout"
docs: {
description: "A description of what the rule does",
category: "Best Practices",
recommended: false,
},
fixable: null, // or "code" if the rule can fix issues automatically
schema: [], // JSON Schema for rule options
},
create(context) {
return {
// Define the rule's behavior here
// e.g., "Identifier": (node) => { /* logic */ }
};
},
};
```

## Step 2: Update the Plugin Index File

1. Open the `index.js` file inside `eslint-plugin` directory.

2. Import your custom rule and add it to the rules object in `index.js`. For example:

```js
const customRule = require("./custom-rule/rule.js");

module.exports = {
rules: {
"custom-rule": customRule,
},
};
```

## Step 3: Add Tests for Your Custom Rule

1. Create a test file for your rule in the `custom-rule` directory. For example, `custom-rule/rule.test.js`.

```bash
touch custom-rule/rule.test.js
```

2. Open `custom-rule/rule.test.js` and write tests using a testing framework like Mocha or Jest. Here's a basic example using ESLint's `RuleTester`:

```js
const rule = require("./rule");
const RuleTester = require("eslint").RuleTester;

const ruleTester = new RuleTester();

ruleTester.run("custom-rule", rule, {
valid: [
// Examples of valid code
],
invalid: [
{
code: "const foo = 1;",
errors: [{ message: "Your custom error message" }],
},
],
});
```

3. Run your tests to ensure your rule works as expected:

```bash
yarn run test:unit
```

## Step 4: Steps to add it to client

1. Go to `app/client/.eslintrc.base.json`
2. Add your `custom-rule` entry to the rules object. e.g.

```javascript
"custom-rule": "warn"
```

## Additional Resources

- [ESLint Plugin Developer Guide](https://eslint.org/docs/developer-guide/working-with-plugins)
- [ESLint Rules API](https://eslint.org/docs/developer-guide/working-with-rules)
- [ESLint Testing Guidelines](https://eslint.org/docs/developer-guide/unit-testing)

Happy linting!
11 changes: 11 additions & 0 deletions app/client/packages/eslint-plugin/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = {
roots: ["<rootDir>/src"],
transform: {
"^.+\\.(ts)$": [
"ts-jest",
{
isolatedModules: true,
},
],
},
};
14 changes: 14 additions & 0 deletions app/client/packages/eslint-plugin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "@appsmith/eslint-plugin",
"version": "1.0.0",
"private": true,
"main": "dist/index.js",
"scripts": {
"build": "npx tsc",
"build:watch": "npx tsc --watch",
"lint": "yarn g:lint",
"prettier": "yarn g:prettier",
"postinstall": "yarn build",
"test:unit": "yarn g:jest"
}
}
16 changes: 16 additions & 0 deletions app/client/packages/eslint-plugin/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { objectKeysRule } from "./object-keys/rule";

const plugin = {
rules: {
"object-keys": objectKeysRule,
},
configs: {
recommended: {
rules: {
"@appsmith/object-keys": "warn",
},
},
},
};

module.exports = plugin;
18 changes: 18 additions & 0 deletions app/client/packages/eslint-plugin/src/object-keys/rule.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { TSESLint } from "@typescript-eslint/utils";
import { objectKeysRule } from "./rule";

const ruleTester = new TSESLint.RuleTester();

ruleTester.run("object-keys", objectKeysRule, {
valid: [
{
code: "objectKeys({ 'a': 'b' })",
},
],
invalid: [
{
code: "Object.keys({ 'a': 'b' })",
errors: [{ messageId: "useObjectKeys" }],
},
],
});
36 changes: 36 additions & 0 deletions app/client/packages/eslint-plugin/src/object-keys/rule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { TSESLint } from "@typescript-eslint/utils";

export const objectKeysRule: TSESLint.RuleModule<"useObjectKeys"> = {
defaultOptions: [],
meta: {
type: "suggestion",
docs: {
description: "Warns when Object.keys is used instead of objectKeys",
recommended: "warn",
},
schema: [], // No options
messages: {
useObjectKeys:
"Use objectKeys from '@appsmith/utils' package instead of Object.keys",
},
},
create(context) {
return {
CallExpression(node) {
// Check if the callee is Object.keys
if (
node.callee.type === "MemberExpression" &&
node.callee.object.type === "Identifier" &&
node.callee.object.name === "Object" &&
node.callee.property.type === "Identifier" &&
node.callee.property.name === "keys"
) {
context.report({
node,
messageId: "useObjectKeys",
});
}
},
};
},
};
11 changes: 11 additions & 0 deletions app/client/packages/eslint-plugin/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"outDir": "dist",
"target": "es2022",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
3 changes: 3 additions & 0 deletions app/client/packages/utils/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": ["../../.eslintrc.base.json"]
}
11 changes: 11 additions & 0 deletions app/client/packages/utils/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = {
roots: ["<rootDir>/src"],
transform: {
AmanAgarwal041 marked this conversation as resolved.
Show resolved Hide resolved
"^.+\\.(ts)$": [
"ts-jest",
{
isolatedModules: true,
},
],
},
};
14 changes: 14 additions & 0 deletions app/client/packages/utils/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "@appsmith/utils",
"version": "1.0.0",
"description": "This package has all the shared util functions which can be used in different packages e.g. client, rts etc",
"main": "src/index.ts",
"types": "src/index.d.ts",
"scripts": {
"lint": "yarn g:lint",
"prettier": "yarn g:prettier",
"test:unit": "yarn g:jest"
},
"author": "Aman Agarwal <aman@appsmith.com>, Pawan Kumar <pawan@appsmith.com>",
"license": "ISC"
}
1 change: 1 addition & 0 deletions app/client/packages/utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./object";
1 change: 1 addition & 0 deletions app/client/packages/utils/src/object/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { objectKeys } from "./keys";
7 changes: 7 additions & 0 deletions app/client/packages/utils/src/object/keys.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { objectKeys } from "./keys";

test("objectKeys should return all the keys in the object map pass to it.", () => {
const objectMap = { a: 1, b: 2, c: 3 };
const keys = objectKeys(objectMap);
expect(keys).toStrictEqual(["a", "b", "c"]);
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
* when looping through the keys. This function returns an array of keys with the correct type information.
*
* with classic Object.keys: Object.keys({ a: 1, b: 2 }) -> string[]
* with objeetKeys: objectKeys({ a: 1, b: 2 }) -> ("a" | "b")[]
* with objectKeys: objectKeys({ a: 1, b: 2 }) -> ("a" | "b")[]
*
* @param object
* @returns array of keys with correct type information
*/
export function objectKeys<T extends object>(object: T) {

export function objectKeys<T extends object>(object: T): Array<keyof T> {
return Object.keys(object) as Array<keyof T>;
}
4 changes: 4 additions & 0 deletions app/client/packages/utils/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.json",
"include": ["./src/**/*"]
}
Loading
Loading