-
-
Notifications
You must be signed in to change notification settings - Fork 148
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ui/eslint): add eslint plugin for artalk ui development
- Implemented `eslint-plugin-artalk` to enforce Artalk's development conventions. - Added setup script for UI development environment. - Created test cases for Artalk plugin rules. - Configured TypeScript and build settings for the plugin. - Updated documentation with installation and configuration instructions.
- Loading branch information
Showing
10 changed files
with
577 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { exec } from 'child_process' | ||
|
||
function runCommand(command) { | ||
return new Promise((resolve, reject) => { | ||
exec(command, (error, stdout, stderr) => { | ||
if (error) { | ||
reject(stderr || stdout) | ||
} else { | ||
resolve(stdout) | ||
} | ||
}) | ||
}) | ||
} | ||
|
||
async function build() { | ||
try { | ||
// Build Artalk Plugin Kit for plugin development | ||
await runCommand('pnpm build:plugin-kit') | ||
const green = '\x1b[32m' | ||
console.log(green, '[ArtalkDev] build @artalk/plugin-kit success') | ||
// Build Artalk eslint plugin for lint checking | ||
await runCommand('pnpm build:eslint-plugin') | ||
console.log(green, '[ArtalkDev] build eslint-plugin-artalk success') | ||
} catch (error) { | ||
console.error('[ArtalkDev] Artalk UI development environment setup failed:', error) | ||
} | ||
} | ||
|
||
build() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
# eslint-plugin-artalk [![npm](https://img.shields.io/npm/v/eslint-plugin-artalk)](https://www.npmjs.com/package/eslint-plugin-artalk) | ||
|
||
The ESLint plugin enforcing Artalk's development conventions. | ||
|
||
It is a part of the [Plugin Development Kit](https://artalk.js.org/develop/plugin.html) for Artalk. | ||
|
||
## Installation | ||
|
||
```bash | ||
pnpm add -D eslint-plugin-artalk | ||
``` | ||
|
||
Since Artalk development is based on TypeScript and the plugin relies on it, you need to install `typescript` and `@typescript-eslint/parser`. For more details, refer to [TypeScript ESLint](https://typescript-eslint.io/getting-started/). | ||
|
||
### Flat Configuration | ||
|
||
Modify the `eslint.config.mjs` file in your project: | ||
|
||
<!-- prettier-ignore --> | ||
```js | ||
import eslintJs from '@eslint/js' | ||
import eslintTs from 'typescript-eslint' | ||
import pluginArtalk from 'eslint-plugin-artalk' | ||
|
||
export default eslintTs.config( | ||
eslintJs.configs.recommended, | ||
...eslintTs.configs.recommended, | ||
{ | ||
files: ['**/*.{ts,mts,cts,tsx,js,mjs,cjs}'], | ||
languageOptions: { | ||
parser: eslintTs.parser, | ||
parserOptions: { | ||
project: './tsconfig.json', | ||
tsconfigRootDir: __dirname, | ||
sourceType: 'module', | ||
}, | ||
}, | ||
plugins: { | ||
artalk: pluginArtalk, | ||
}, | ||
rules: { | ||
...pluginArtalk.configs.recommended.rules, | ||
}, | ||
} | ||
) | ||
``` | ||
|
||
<!-- prettier-ignore-end --> | ||
|
||
### Custom Configuration | ||
|
||
You can customize the rules by modifying the `rules` field in the configuration: | ||
|
||
```js | ||
{ | ||
plugins: { | ||
artalk: pluginArtalk, | ||
}, | ||
rules: { | ||
'artalk/artalk-plugin': 'error', | ||
}, | ||
} | ||
``` | ||
|
||
## Valid and Invalid Examples | ||
|
||
### Rule `artalk-plugin` | ||
|
||
The ESLint rule `artalk/artalk-plugin` enforces the conventions for Artalk plugins. | ||
|
||
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` | ||
|
||
Should not allow life-cycle event listeners to be defined inside nested blocks. | ||
|
||
The life-cycle event listeners are `created`, `mounted`, `updated`, and `destroyed` must be defined in the top-level scope of the ArtalkPlugin arrow function. | ||
|
||
**⚠️ Fail**: | ||
|
||
```ts | ||
import type { ArtalkPlugin } from 'artalk' | ||
|
||
export const TestPlugin: ArtalkPlugin = (ctx) => { | ||
const foo = () => { | ||
const bar = () => { | ||
ctx.on('updated', () => {}) | ||
} | ||
} | ||
} | ||
``` | ||
|
||
**✅ Pass**: | ||
|
||
```ts | ||
import type { ArtalkPlugin } from 'artalk' | ||
|
||
export const TestPlugin: ArtalkPlugin = (ctx) => { | ||
ctx.on('updated', () => {}) | ||
} | ||
``` | ||
|
||
#### `noEventInWatchConf` | ||
|
||
Should not allow event listeners to be defined inside watchConf effect function. | ||
|
||
**⚠️ Fail**: | ||
|
||
```ts | ||
import type { ArtalkPlugin } from 'artalk' | ||
|
||
export const TestPlugin: ArtalkPlugin = (ctx) => { | ||
ctx.watchConf(['el'], (conf) => { | ||
ctx.on('update', () => {}) | ||
}) | ||
} | ||
``` | ||
|
||
## License | ||
|
||
[MIT](https://github.com/ArtalkJS/Artalk/blob/master/LICENSE) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{ | ||
"name": "eslint-plugin-artalk", | ||
"version": "1.0.0", | ||
"type": "module", | ||
"license": "MIT", | ||
"homepage": "https://github.com/ArtalkJS/Artalk/tree/master/ui/eslint-plugin-artalk", | ||
"files": [ | ||
"dist", | ||
"README.md" | ||
], | ||
"main": "dist/main.js", | ||
"types": "dist/main.d.ts", | ||
"exports": { | ||
".": { | ||
"require": { | ||
"types": "./dist/main.d.cjs", | ||
"default": "./dist/main.cjs" | ||
}, | ||
"default": { | ||
"types": "./dist/main.d.ts", | ||
"default": "./dist/main.js" | ||
} | ||
} | ||
}, | ||
"scripts": { | ||
"dev": "tsup --watch", | ||
"build": "tsup", | ||
"test": "vitest" | ||
}, | ||
"devDependencies": { | ||
"@typescript-eslint/rule-tester": "^8.8.0", | ||
"tsup": "^8.3.0" | ||
}, | ||
"peerDependencies": { | ||
"@typescript-eslint/utils": ">=8", | ||
"eslint": ">=9" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { artalkPlugin } from './artalk-plugin' | ||
import { setupTest } from './test-helper' | ||
|
||
const { ruleTester } = setupTest() | ||
|
||
const invalid = [ | ||
{ | ||
name: 'should not allow life-cycle event functions in nested blocks', | ||
code: ` | ||
import type { ArtalkPlugin } from 'artalk' | ||
export const TestPlugin: ArtalkPlugin = (ctx) => { | ||
const foo = () => { | ||
const bar = () => { | ||
ctx.on('updated', () => {}) | ||
} | ||
} | ||
} | ||
`, | ||
errorId: 'noLifeCycleEventInNestedBlocks', | ||
}, | ||
{ | ||
name: "should not allow 'off' call inside watchConf effect", | ||
code: ` | ||
import type { ArtalkPlugin } from 'artalk' | ||
export const TestPlugin: ArtalkPlugin = (ctx) => { | ||
ctx.watchConf(['pageVote'], (conf) => { | ||
ctx.off('updated', () => {}) | ||
}) | ||
} | ||
`, | ||
errorId: 'noEventInWatchConf', | ||
}, | ||
] | ||
|
||
for (const { name, code, errorId } of invalid) { | ||
ruleTester.run(name, artalkPlugin as any, { | ||
valid: [], | ||
invalid: [{ code, errors: [{ messageId: errorId }] }], | ||
}) | ||
} |
Oops, something went wrong.