Skip to content

Commit

Permalink
feat(ui/eslint): update eslint-plugin-artalk to v1.0.2 (#1010)
Browse files Browse the repository at this point in the history
- Add new ESLint rules for ArtalkPlugin:
  - Available rules: `noCycleDeps`, `noLifeCycleEventInNestedBlocks`, `noEventInWatchConf`, `noInjectInNestedBlocks`, `noInjectOutsidePlugin`, `onePluginPerFile`. For more details, see [eslint-plugin-artalk](https://github.com/ArtalkJS/Artalk/tree/master/ui/eslint-plugin-artalk).
- Add tests for the new ESLint rules.
- Implement Tarjan's algorithm for detecting SCCs in the `noCycleDeps` rule.
- Improve code organization and maintainability.
- Disable the 'import-x/namespace' rule for better performance. (import-js/eslint-plugin-import#2340)
  • Loading branch information
qwqcode authored Oct 18, 2024
1 parent dcde53f commit f6c99e9
Show file tree
Hide file tree
Showing 10 changed files with 719 additions and 256 deletions.
1 change: 1 addition & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export default eslintTs.config(
'import-x/no-named-as-default-member': 'off',
'import-x/no-named-as-default': 'off',
'import-x/default': 'off', // fix https://github.com/import-js/eslint-plugin-import/issues/1800
'import-x/namespace': 'off', // very slow, see https://github.com/import-js/eslint-plugin-import/issues/2340
'import-x/order': 'warn',
},
settings: {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"eslint": "^9.10.0",
"eslint-config-prettier": "9.1.0",
"eslint-import-resolver-typescript": "3.6.3",
"eslint-plugin-artalk": "^1.0.1",
"eslint-plugin-artalk": "^1.0.2",
"eslint-plugin-compat": "^6.0.1",
"eslint-plugin-import-x": "^4.2.1",
"eslint-plugin-react": "^7.36.1",
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

157 changes: 153 additions & 4 deletions ui/eslint-plugin-artalk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,69 @@ The ESLint rule `artalk/artalk-plugin` enforces the conventions for Artalk plugi

The ESLint rule is only enabled when a TypeScript file imports the `ArtalkPlugin` type from the `artalk` package and defines an arrow function variable with the type `ArtalkPlugin`, such as `const TestPlugin: ArtalkPlugin = (ctx) => {}`. The variable type must be `ArtalkPlugin`.

#### `noLifeCycleEventInNestedBlocks`
#### `noCycleDeps`

Should not allow life-cycle event listeners to be defined inside nested blocks.
Circular dependencies should not be allowed in the `provide` method. The method must not inject a dependency that it also provides, including indirect circular references (e.g., `a` -> `b` -> `c` -> `a`).

The life-cycle event listeners are `created`, `mounted`, `updated`, and `destroyed` must be defined in the top-level scope of the ArtalkPlugin arrow function.
The best way to deal with this situation is to do some kind of refactor to avoid the cyclic dependencies.

**⚠️ Fail**:

```ts
import type { ArtalkPlugin } from 'artalk'

export const TestPlugin: ArtalkPlugin = (ctx) => {
ctx.provide('foo', (foo) => {}, ['foo'])
}
```

```ts
import type { ArtalkPlugin } from 'artalk'

// foo.ts
const FooPlugin: ArtalkPlugin = (ctx) => {
ctx.provide('foo', (bar) => {}, ['bar'])
}

// bar.ts
const BarPlugin: ArtalkPlugin = (ctx) => {
ctx.provide('bar', (foo) => {}, ['foo'])
}
```

**✅ Pass**:

You can introduce a mediator to resolve circular dependencies. The mediator will handle interactions between the dependencies, breaking the direct circular relationship while maintaining their communication through the mediator.

```ts
import type { ArtalkPlugin } from 'artalk'

// foo.ts
const FooPlugin: ArtalkPlugin = (ctx) => {
ctx.provide('foo', () => {})
}

// bar.ts
const BarPlugin: ArtalkPlugin = (ctx) => {
ctx.provide('bar', () => {})
}

// mediator.ts
const MediatorPlugin: ArtalkPlugin = (ctx) => {
ctx.provide(
'mediator',
(foo, bar) => {
// ...
// interact with foo and bar
},
['foo', 'bar'],
)
}
```

#### `noLifeCycleEventInNestedBlocks`

Life-cycle event listeners such as `created`, `mounted`, `updated`, and `destroyed` should not be defined inside nested blocks. They must be placed in the top-level scope of the `ArtalkPlugin` arrow function to ensure clarity and maintainability.

**⚠️ Fail**:

Expand Down Expand Up @@ -102,7 +160,7 @@ export const TestPlugin: ArtalkPlugin = (ctx) => {

#### `noEventInWatchConf`

Should not allow event listeners to be defined inside watchConf effect function.
Event listeners should not be defined inside the `watchConf` effect function. They must be placed outside to ensure proper separation of concerns and to avoid unintended side effects.

**⚠️ Fail**:

Expand All @@ -116,6 +174,97 @@ export const TestPlugin: ArtalkPlugin = (ctx) => {
}
```

**✅ Pass**:

```ts
import type { ArtalkPlugin } from 'artalk'

export const TestPlugin: ArtalkPlugin = (ctx) => {
ctx.on('update', () => {})

ctx.watchConf(['el'], (conf) => {})
}
```

#### `noInjectInNestedBlocks`

The `inject` method should not be called inside nested blocks. It must be used at the top-level scope of the `ArtalkPlugin` arrow function. For better readability and maintainability, it is recommended to place the `inject` call at the beginning of the function.

**⚠️ Fail**:

```ts
import type { ArtalkPlugin } from 'artalk'

export const TestPlugin: ArtalkPlugin = (ctx) => {
const fn = () => {
const foo = ctx.inject('foo')
}
}
```

**✅ Pass**:

```ts
import type { ArtalkPlugin } from 'artalk'

export const TestPlugin: ArtalkPlugin = (ctx) => {
const foo = ctx.inject('foo')
}
```

#### `noInjectOutsidePlugin`

The `inject` method should not be called outside the `ArtalkPlugin` arrow function. It must be used in the top-level scope of the `ArtalkPlugin` function to ensure the dependency injection remains readable and maintainable.

**⚠️ Fail**:

```ts
function fn(ctx) {
const foo = ctx.inject('foo')
}
```

**✅ Pass**:

```ts
import type { ArtalkPlugin } from 'artalk'

export const TestPlugin: ArtalkPlugin = (ctx) => {
const foo = ctx.inject('foo')
}
```

#### `onePluginPerFile`

Multiple plugins should not be defined in the same file. Each plugin must be defined in its own separate file to improve code organization and maintainability.

**⚠️ Fail**:

```ts
import type { ArtalkPlugin } from 'artalk'

export const TestPlugin: ArtalkPlugin = (ctx) => {}
export const AnotherPlugin: ArtalkPlugin = (ctx) => {}
```

**✅ Pass**:

TestPlugin.ts:

```ts
import type { ArtalkPlugin } from 'artalk'

export const TestPlugin: ArtalkPlugin = (ctx) => {}
```

AnotherPlugin.ts:

```ts
import type { ArtalkPlugin } from 'artalk'

export const AnotherPlugin: ArtalkPlugin = (ctx) => {}
```

## License

[MIT](https://github.com/ArtalkJS/Artalk/blob/master/LICENSE)
2 changes: 1 addition & 1 deletion ui/eslint-plugin-artalk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eslint-plugin-artalk",
"version": "1.0.1",
"version": "1.0.2",
"type": "module",
"license": "MIT",
"homepage": "https://github.com/ArtalkJS/Artalk/tree/master/ui/eslint-plugin-artalk",
Expand Down
Loading

0 comments on commit f6c99e9

Please sign in to comment.