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

add eslint #5041

Merged
merged 17 commits into from
Sep 29, 2024
Merged

Conversation

with-heart
Copy link
Contributor

This PR installs and configures eslint with typescript-eslint.

It uses the new flat config format (which is such a nice improvement imo), along with the recommended rules from @eslint/js and typescript-eslint.

Since #5022 is a thing, I added all test.* files to the global ignores. Once that lands we can remove this and maybe add eslint-plugin-vitest.

Copy link

changeset-bot bot commented Aug 16, 2024

⚠️ No Changeset found

Latest commit: aee03ce

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@with-heart
Copy link
Contributor Author

I wanted to try this with type-aware linting but it reported hundreds of errors that didn't seem like they'd be easy to fix. They're likely related to having to set @typescript-eslint/no-explicit-any to warn (581 warnings for that rule alone 😬).

@Andarist
Copy link
Member

how many we'd get after disabling @typescript-eslint/no-explicit-any?

@with-heart
Copy link
Contributor Author

@Andarist 0. Should we disable it? I wasn't sure if this was something that'd be worth trying to deal with or not

@with-heart
Copy link
Contributor Author

with-heart commented Aug 16, 2024

I'm not sure what the deal is with the failed check. The error it reports isn't actually relevant.

Here's the actual error:

This syntax is reserved in files with the .mts or .cts extension. Add a trailing comma, as in `<T,>() => ...`. (20:14)

To make build work, I have to add a trailing comma to type params in packages/xstate-solid:

diff --git a/packages/xstate-solid/src/createImmutable.ts b/packages/xstate-solid/src/createImmutable.ts
index 5624473d5b..e3237c7414 100644
--- a/packages/xstate-solid/src/createImmutable.ts
+++ b/packages/xstate-solid/src/createImmutable.ts
@@ -19,7 +19,7 @@ const updateStore = <Path extends unknown[]>(
   store: Store<any>
 ) => {
   const valueRefs = new WeakMap<any, unknown>();
-  const diff = <CompareValue>(
+  const diff = <CompareValue,>(
     next: CompareValue,
     prev: CompareValue,
     path: Path
diff --git a/packages/xstate-solid/src/deepClone.ts b/packages/xstate-solid/src/deepClone.ts
index e829300845..58bc92e28d 100644
--- a/packages/xstate-solid/src/deepClone.ts
+++ b/packages/xstate-solid/src/deepClone.ts
@@ -17,7 +17,7 @@ export function isWrappable(obj: any): obj is object {
  * @param valueRefs A WeakMap that stores a reference from the original
  *   object/array to the cloned object/array
  */
-const clone = <T>(value: T, valueRefs: WeakMap<any, any>): T => {
+const clone = <T,>(value: T, valueRefs: WeakMap<any, any>): T => {
   if (!isWrappable(value)) {
     return value;
   }
@@ -47,4 +47,4 @@ const clone = <T>(value: T, valueRefs: WeakMap<any, any>): T => {
   return clonedValue;
 };
 
-export const deepClone = <T>(value: T): T => clone(value, new WeakMap());
+export const deepClone = <T,>(value: T): T => clone(value, new WeakMap());

These previously used extends unknown:

diff --git a/packages/xstate-solid/src/createImmutable.ts b/packages/xstate-solid/src/createImmutable.ts
index 7764371bac..e3237c7414 100644
--- a/packages/xstate-solid/src/createImmutable.ts
+++ b/packages/xstate-solid/src/createImmutable.ts
@@ -19,7 +19,7 @@ const updateStore = <Path extends unknown[]>(
   store: Store<any>
 ) => {
   const valueRefs = new WeakMap<any, unknown>();
-  const diff = <CompareValue extends unknown>(
+  const diff = <CompareValue,>(
     next: CompareValue,
     prev: CompareValue,
     path: Path
diff --git a/packages/xstate-solid/src/deepClone.ts b/packages/xstate-solid/src/deepClone.ts
index 1eeaa76a2d..58bc92e28d 100644
--- a/packages/xstate-solid/src/deepClone.ts
+++ b/packages/xstate-solid/src/deepClone.ts
@@ -17,10 +17,7 @@ export function isWrappable(obj: any): obj is object {
  * @param valueRefs A WeakMap that stores a reference from the original
  *   object/array to the cloned object/array
  */
-const clone = <T extends unknown>(
-  value: T,
-  valueRefs: WeakMap<any, any>
-): T => {
+const clone = <T,>(value: T, valueRefs: WeakMap<any, any>): T => {
   if (!isWrappable(value)) {
     return value;
   }
@@ -50,5 +47,4 @@ const clone = <T extends unknown>(
   return clonedValue;
 };
 
-export const deepClone = <T extends unknown>(value: T): T =>
-  clone(value, new WeakMap());
+export const deepClone = <T,>(value: T): T => clone(value, new WeakMap());

Not really sure what the issue is here and prettier removes the dangling commas so it's not really a fix.

@boneskull
Copy link
Contributor

I wanted to try this with type-aware linting but it reported hundreds of errors that didn't seem like they'd be easy to fix. They're likely related to having to set @typescript-eslint/no-explicit-any to warn (581 warnings for that rule alone 😬).

IMO this is worth doing. You will probably need to disable stuff if using the recommendedTypeChecked preview; it's pretty strict.

Here's some of the rules I'd suggest tweaking:

// and sometimes you gotta use any
'@typescript-eslint/no-explicit-any': 'off',

// allow ! 
'@typescript-eslint/no-non-null-assertion': 'off',

// allow prefixing unused vars with _
'@typescript-eslint/no-unused-vars': [
  'error',
  {
    argsIgnorePattern: '^_',
    varsIgnorePattern: '^_',
  },
],

// better for overloads
'@typescript-eslint/unified-signatures': [
  'error',
  {
    ignoreDifferentlyNamedParameters: true,
  },
],

Something like the above might get you out of the woods.

Also I'd recommend enabling this (if it's not already enabled by default), which surfaces unused // eslint-disable directives:

{
  linterOptions: {
    reportUnusedDisableDirectives: 'error',
  },
}

I'm not sure what you were using for the parser config, but this is what has worked well for me with tseslint@v8.

languageOptions: {
  parserOptions: {
    projectService: {
      // type-aware linting for non-project config files. modify as necessary
      allowDefaultProject: ['*.js', '.*.js'],
    },
    tsconfigRootDir: import.meta.dirname, // (or __dirname, depending)
  },
},

@boneskull
Copy link
Contributor

I don't think T extends unknown is doing anything in that function, and can just be T.

@davidkpiano
Copy link
Member

@with-heart Can you resolve merge conflicts?

@with-heart
Copy link
Contributor Author

@with-heart Can you resolve merge conflicts?

Done! I think we should be good to go assuming the changes look fine 🙏

Copy link
Member

@davidkpiano davidkpiano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc. @Andarist

@@ -109,7 +109,7 @@ export interface Store<

export type AnyStore = Store<any, any, any>;

export type Compute<A extends any> = { [K in keyof A]: A[K] } & unknown;
export type Compute<A> = { [K in keyof A]: A[K] };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

& unknown is required sometimes

Suggested change
export type Compute<A> = { [K in keyof A]: A[K] };
export type Compute<A> = { [K in keyof A]: A[K] } & unknown;

Comment on lines +20 to 21
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint
const clone = <T extends unknown>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would this work instead?

Suggested change
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint
const clone = <T extends unknown>(
const clone = <T,>(

@@ -41,7 +41,7 @@ export type GetParameterizedParams<T extends ParameterizedObject | undefined> =
* This type can be used to avoid this problem. This union represents the same
* value space as `unknown`.
*/
export type NonReducibleUnknown = {} | null | undefined;
export type NonReducibleUnknown = NonNullable<unknown> | null | undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I officially hate this... 😂 I kinda understand why {} has such a bad rep... but if I'll have to start using NonNullable<unknown> everywhere to workaround a lint rule... 😬

Personally, I'd vote for disabling that rule and allowing {}

Comment on lines +118 to +119
_args: GuardArgs<TContext, TExpressionEvent>,
_params: TParams
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

those might be seen by users when debugging in devtools, I think it would be best to avoid _ for those

@@ -102,8 +101,8 @@ export function stopChild<
actorRef: ResolvableActorRef<TContext, TExpressionEvent, TParams, TEvent>
): StopAction<TContext, TExpressionEvent, TParams, TEvent> {
function stop(
args: ActionArgs<TContext, TExpressionEvent, TEvent>,
params: TParams
_args: ActionArgs<TContext, TExpressionEvent, TEvent>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same in all of those actions

davidkpiano and others added 3 commits September 28, 2024 14:32
@davidkpiano davidkpiano changed the base branch from main to davidkpiano/with-heart-eslint September 29, 2024 16:12
@davidkpiano davidkpiano merged commit ca0a5f8 into statelyai:davidkpiano/with-heart-eslint Sep 29, 2024
1 check failed
@davidkpiano davidkpiano mentioned this pull request Sep 29, 2024
davidkpiano added a commit that referenced this pull request Oct 2, 2024
* add eslint (#5041)

* remove tslint.json

* install and configure eslint

* resolve lint errors

* add eslint to ci-checks

* enable eslint type-checked rules

* fix type-check errors

* add eslint fix commits to .git-blame-ignore-revs

* allow empty object types

* disable no-unnecessary-type-constraints on specific lines

* revert removal of non-conforming type check in actions

* resolve lint errors

* Update packages/core/src/types.ts

Co-authored-by: Mateusz Burzyński <[email protected]>

* Update packages/core/src/types.ts

Co-authored-by: Mateusz Burzyński <[email protected]>

* Update packages/xstate-inspect/src/server.ts

Co-authored-by: Mateusz Burzyński <[email protected]>

---------

Co-authored-by: David Khourshid <[email protected]>
Co-authored-by: Mateusz Burzyński <[email protected]>

* Fix lint issues

---------

Co-authored-by: with-heart <[email protected]>
Co-authored-by: Mateusz Burzyński <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants