Skip to content

Commit a80c59f

Browse files
authored
feat: adds eslint 9 config (#19)
* eslint 9 config * tests fix * fixes clean command * coderabbit feedback
1 parent 0e3be08 commit a80c59f

File tree

12 files changed

+1366
-2658
lines changed

12 files changed

+1366
-2658
lines changed

apps/playground/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"build": "next build",
88
"start": "next start",
99
"lint": "next lint --max-warnings 0",
10-
"check-types": "tsc --noEmit"
10+
"check-types": "tsc --noEmit",
11+
"clean": "rimraf .turbo node_modules dist coverage"
1112
},
1213
"dependencies": {
1314
"lucide-react": "0.544.0",

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,17 @@
88
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
99
"check-types": "turbo run check-types",
1010
"test": "turbo run test --no-cache",
11-
"test:coverage": "turbo run test:coverage --no-cache"
11+
"test:coverage": "turbo run test:coverage --no-cache",
12+
"clean": "turbo run clean && rimraf node_modules .turbo coverage out"
1213
},
1314
"devDependencies": {
1415
"prettier": "^3.6.2",
1516
"turbo": "^2.5.8",
16-
"typescript": "5.9.3"
17+
"typescript": "5.9.3",
18+
"rimraf": "6.0.1"
1719
},
1820
"packageManager": "pnpm@10.18.0",
1921
"engines": {
20-
"node": ">=18"
22+
"node": ">=18.18.0"
2123
}
2224
}

packages/js/.eslintrc.cjs

Lines changed: 0 additions & 48 deletions
This file was deleted.

packages/js/eslint.config.mjs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import js from "@eslint/js";
2+
import tseslint from "typescript-eslint";
3+
import vitest from "@vitest/eslint-plugin";
4+
import eslintConfigPrettier from "eslint-config-prettier";
5+
import importPlugin from "eslint-plugin-import";
6+
import checkFilePlugin from "eslint-plugin-check-file";
7+
import prettierPlugin from "eslint-plugin-prettier";
8+
import { fileURLToPath } from "url";
9+
import { dirname } from "path";
10+
11+
const __dirname = dirname(fileURLToPath(import.meta.url));
12+
13+
/**
14+
* A shared ESLint configuration for the repository.
15+
*
16+
* @type {import("eslint").Linter.Config[]}
17+
* */
18+
export default [
19+
// Ignore patterns
20+
{
21+
ignores: [
22+
"node_modules/",
23+
"dist/",
24+
"coverage/",
25+
"*.config.js",
26+
"*.config.ts",
27+
"*.config.mjs",
28+
"*.d.ts",
29+
],
30+
},
31+
32+
// Base ESLint recommended rules
33+
js.configs.recommended,
34+
35+
// Prettier rules
36+
eslintConfigPrettier,
37+
38+
// TypeScript ESLint recommended rules
39+
...tseslint.configs.recommendedTypeChecked,
40+
...tseslint.configs.stylisticTypeChecked,
41+
42+
// Main configuration
43+
{
44+
plugins: {
45+
import: importPlugin,
46+
"check-file": checkFilePlugin,
47+
prettier: prettierPlugin,
48+
},
49+
languageOptions: {
50+
parserOptions: {
51+
projectService: true,
52+
tsconfigRootDir: __dirname,
53+
},
54+
},
55+
rules: {
56+
// no unused vars errors out but not when we use _
57+
"@typescript-eslint/no-unused-vars": [
58+
"error",
59+
{
60+
argsIgnorePattern: "^_",
61+
varsIgnorePattern: "^_",
62+
},
63+
],
64+
65+
// Import hygiene
66+
"import/no-duplicates": "error",
67+
"import/newline-after-import": "warn",
68+
69+
"check-file/filename-naming-convention": [
70+
"error",
71+
{ "**/*.{ts,tsx}": "KEBAB_CASE" },
72+
{ ignoreMiddleExtensions: true },
73+
],
74+
"prettier/prettier": "error",
75+
},
76+
},
77+
78+
// Vitest test files configuration
79+
{
80+
files: ["**/*.{test,spec}.ts", "**/*.{test,spec}.tsx"],
81+
plugins: {
82+
vitest,
83+
},
84+
rules: {
85+
"vitest/consistent-test-it": [
86+
"error",
87+
{ fn: "test", withinDescribe: "test" },
88+
],
89+
},
90+
settings: {
91+
vitest: {
92+
typecheck: true,
93+
},
94+
},
95+
},
96+
];

packages/js/package.json

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,24 @@
3535
"build": "tsc && vite build",
3636
"build:dev": "tsc && vite build --mode dev",
3737
"go": "vite build --watch --mode dev",
38-
"lint": "eslint . --ext .ts,.js,.tsx,.jsx",
39-
"clean": "rimraf .turbo node_modules dist coverage",
38+
"lint": "eslint .",
4039
"test": "vitest run",
41-
"test:coverage": "vitest run --coverage"
40+
"test:coverage": "vitest run --coverage",
41+
"clean": "rimraf .turbo node_modules dist coverage"
4242
},
4343
"author": "Formbricks <hola@formbricks.com>",
4444
"devDependencies": {
45-
"@vercel/style-guide": "6.0.0",
45+
"@eslint/js": "9.37.0",
4646
"@vitest/coverage-v8": "3.2.4",
47+
"@vitest/eslint-plugin": "1.3.16",
48+
"eslint": "9.37.0",
49+
"eslint-config-prettier": "10.1.8",
50+
"eslint-plugin-check-file": "3.3.0",
51+
"eslint-plugin-import": "2.32.0",
52+
"eslint-plugin-prettier": "5.5.4",
53+
"happy-dom": "19.0.2",
4754
"terser": "5.44.0",
55+
"typescript-eslint": "8.46.0",
4856
"vite": "7.1.9",
4957
"vite-plugin-dts": "4.5.4",
5058
"vitest": "3.2.4"

packages/js/src/index.test.ts

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ vi.mock("./lib/load-formbricks", () => ({
77

88
import formbricks from "./index";
99
import * as loadFormbricksModule from "./lib/load-formbricks";
10+
import { TFormbricks } from "./types/formbricks";
1011

1112
// Get the mocked function
1213
const mockLoadFormbricksToProxy = vi.mocked(
13-
loadFormbricksModule.loadFormbricksToProxy
14+
loadFormbricksModule.loadFormbricksToProxy,
1415
);
1516

1617
describe("formbricks proxy", () => {
@@ -60,7 +61,7 @@ describe("formbricks proxy", () => {
6061
expect(mockLoadFormbricksToProxy).toHaveBeenCalledWith(
6162
"setAttribute",
6263
key,
63-
value
64+
value,
6465
);
6566
});
6667

@@ -74,7 +75,7 @@ describe("formbricks proxy", () => {
7475

7576
expect(mockLoadFormbricksToProxy).toHaveBeenCalledWith(
7677
"setAttributes",
77-
attributes
78+
attributes,
7879
);
7980
});
8081

@@ -85,7 +86,7 @@ describe("formbricks proxy", () => {
8586

8687
expect(mockLoadFormbricksToProxy).toHaveBeenCalledWith(
8788
"setLanguage",
88-
language
89+
language,
8990
);
9091
});
9192

@@ -107,7 +108,7 @@ describe("formbricks proxy", () => {
107108
await formbricks.registerRouteChange();
108109

109110
expect(mockLoadFormbricksToProxy).toHaveBeenCalledWith(
110-
"registerRouteChange"
111+
"registerRouteChange",
111112
);
112113
});
113114

@@ -121,7 +122,7 @@ describe("formbricks proxy", () => {
121122
},
122123
};
123124

124-
await (formbricks as any).init(initConfig);
125+
await formbricks.init(initConfig);
125126

126127
expect(mockLoadFormbricksToProxy).toHaveBeenCalledWith("init", initConfig);
127128
});
@@ -136,32 +137,30 @@ describe("formbricks proxy", () => {
136137
},
137138
};
138139

139-
// Cast to any to access the extended track method with properties
140-
await (formbricks as any).track(trackCode, properties);
140+
await formbricks.track(trackCode, properties);
141141

142142
expect(mockLoadFormbricksToProxy).toHaveBeenCalledWith(
143143
"track",
144144
trackCode,
145-
properties
145+
properties,
146146
);
147147
});
148148

149149
test("should handle any method call through the proxy", async () => {
150-
const customMethod = "customMethod";
151-
const args = ["arg1", "arg2", { key: "value" }];
150+
const customMethod: keyof TFormbricks = "track";
151+
const args = ["arg1"];
152152

153-
// Cast to any to call a method that doesn't exist in the type definition
154-
await (formbricks as any)[customMethod](...args);
153+
await formbricks[customMethod](args[0]);
155154

156155
expect(mockLoadFormbricksToProxy).toHaveBeenCalledWith(
157156
customMethod,
158-
...args
157+
args[0],
159158
);
160159
});
161160

162161
test("should return the result of loadFormbricksToProxy calls", async () => {
163162
const mockResult = "test-result";
164-
mockLoadFormbricksToProxy.mockResolvedValue(mockResult as any);
163+
mockLoadFormbricksToProxy.mockResolvedValue(mockResult as unknown as void);
165164

166165
const result = await formbricks.setEmail("test@example.com");
167166

@@ -173,7 +172,7 @@ describe("formbricks proxy", () => {
173172
mockLoadFormbricksToProxy.mockRejectedValue(error);
174173

175174
await expect(formbricks.setEmail("test@example.com")).rejects.toThrow(
176-
"Test error"
175+
"Test error",
177176
);
178177
});
179178

@@ -190,12 +189,12 @@ describe("formbricks proxy", () => {
190189
expect(mockLoadFormbricksToProxy).toHaveBeenCalledTimes(4);
191190
expect(mockLoadFormbricksToProxy).toHaveBeenCalledWith(
192191
"setEmail",
193-
"test@example.com"
192+
"test@example.com",
194193
);
195194
expect(mockLoadFormbricksToProxy).toHaveBeenCalledWith(
196195
"setAttribute",
197196
"userId",
198-
"user123"
197+
"user123",
199198
);
200199
expect(mockLoadFormbricksToProxy).toHaveBeenCalledWith("track", "event1");
201200
expect(mockLoadFormbricksToProxy).toHaveBeenCalledWith("setLanguage", "en");
@@ -226,7 +225,7 @@ describe("proxy behavior", () => {
226225

227226
expect(mockLoadFormbricksToProxy).toHaveBeenCalledWith(
228227
"setUserId",
229-
"user123"
228+
"user123",
230229
);
231230
});
232231

@@ -236,7 +235,7 @@ describe("proxy behavior", () => {
236235
expect(mockLoadFormbricksToProxy).toHaveBeenCalledWith(
237236
"setAttribute",
238237
"key",
239-
"value"
238+
"value",
240239
);
241240
});
242241

@@ -250,7 +249,7 @@ describe("proxy behavior", () => {
250249

251250
expect(mockLoadFormbricksToProxy).toHaveBeenCalledWith(
252251
"setup",
253-
setupConfig
252+
setupConfig,
254253
);
255254
});
256255
});
@@ -264,15 +263,15 @@ describe("type safety", () => {
264263
test("should maintain type safety for known methods", () => {
265264
// These should compile without errors due to proper typing
266265
const testTypeSafety = () => {
267-
formbricks.setup({ environmentId: "env", appUrl: "url" });
268-
formbricks.track("event");
269-
formbricks.setEmail("email");
270-
formbricks.setAttribute("key", "value");
271-
formbricks.setAttributes({ key: "value" });
272-
formbricks.setLanguage("en");
273-
formbricks.setUserId("user");
274-
formbricks.logout();
275-
formbricks.registerRouteChange();
266+
void formbricks.setup({ environmentId: "env", appUrl: "url" });
267+
void formbricks.track("event");
268+
void formbricks.setEmail("email");
269+
void formbricks.setAttribute("key", "value");
270+
void formbricks.setAttributes({ key: "value" });
271+
void formbricks.setLanguage("en");
272+
void formbricks.setUserId("user");
273+
void formbricks.logout();
274+
void formbricks.registerRouteChange();
276275
};
277276

278277
expect(testTypeSafety).not.toThrow();

packages/js/src/index.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,13 @@ declare global {
1414
const formbricksProxyHandler: ProxyHandler<TFormbricks> = {
1515
get(_target, prop, _receiver) {
1616
return (...args: unknown[]) =>
17-
loadFormbricksToProxy(prop as string, ...args);
17+
loadFormbricksToProxy(prop as keyof TFormbricks, ...args);
1818
},
1919
};
2020

2121
const formbricks: TFormbricksCore = new Proxy(
2222
{} as TFormbricks,
23-
formbricksProxyHandler
23+
formbricksProxyHandler,
2424
);
2525

26-
// eslint-disable-next-line import/no-default-export -- Required for UMD
2726
export default formbricks;

0 commit comments

Comments
 (0)