eslint-plugin-light 1.0.17 → 1.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +128 -24
- package/lib/rules/no-decimal-in-brackets.js +53 -0
- package/lib/rules/no-non-index-import.js +142 -0
- package/lib/test/index.js +5 -0
- package/lib/test/no-decimal-in-brackets.js +35 -0
- package/lib/test/no-non-index-import.js +55 -0
- package/package.json +6 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
## <small>1.0.19 (2025-12-12)</small>
|
|
2
|
+
|
|
3
|
+
* chore: update docs ([dc64df7](https://github.com/novlan1/plugin-light/commits/dc64df7))
|
|
4
|
+
* chore: update docs ([bd72447](https://github.com/novlan1/plugin-light/commits/bd72447))
|
|
5
|
+
* chore: update t-comm@2.0.16 ([8c5d294](https://github.com/novlan1/plugin-light/commits/8c5d294))
|
|
6
|
+
* chore: use updateManifestCore of t-comm ([1c149ab](https://github.com/novlan1/plugin-light/commits/1c149ab))
|
|
7
|
+
* chore(eslint-plugin-light): add no-non-index-import ([64a7b0b](https://github.com/novlan1/plugin-light/commits/64a7b0b))
|
|
8
|
+
* docs: update docs ([43f864d](https://github.com/novlan1/plugin-light/commits/43f864d))
|
|
9
|
+
* docs: update docs ([c88907f](https://github.com/novlan1/plugin-light/commits/c88907f))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## <small>1.0.18 (2025-08-08)</small>
|
|
14
|
+
|
|
15
|
+
* feat(eslint): add no-decimal-in-brackets rule ([a4c2b0d](https://github.com/novlan1/plugin-light/commits/a4c2b0d))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
1
19
|
## <small>1.0.17 (2025-07-23)</small>
|
|
2
20
|
|
|
3
21
|
* feat(eslint-plugin): add no-direct-img-src rule ([4223182](https://github.com/novlan1/plugin-light/commits/4223182))
|
package/README.md
CHANGED
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
|
|
12
12
|
简单、易用的 ESLint 插件库。
|
|
13
13
|
|
|
14
|
-
## 1.
|
|
14
|
+
## 1. 作者
|
|
15
|
+
|
|
16
|
+
**novlan1**
|
|
17
|
+
|
|
18
|
+
## 2. 安装
|
|
15
19
|
|
|
16
20
|
首先要安装 [ESLint](https://eslint.org/)。
|
|
17
21
|
|
|
@@ -25,7 +29,7 @@ pnpm i eslint -D
|
|
|
25
29
|
npm i eslint-plugin-light -D
|
|
26
30
|
```
|
|
27
31
|
|
|
28
|
-
##
|
|
32
|
+
## 3. 使用
|
|
29
33
|
|
|
30
34
|
在 `.eslintrc` 配置文件的 `plugins` 中增加本插件 `eslint-plugin-light`,或者省略 `eslint-plugin-` 前缀。
|
|
31
35
|
|
|
@@ -55,9 +59,9 @@ npm i eslint-plugin-light -D
|
|
|
55
59
|
}
|
|
56
60
|
```
|
|
57
61
|
|
|
58
|
-
##
|
|
62
|
+
## 4. 规则
|
|
59
63
|
|
|
60
|
-
###
|
|
64
|
+
### 4.1. valid-vue-comp-import
|
|
61
65
|
|
|
62
66
|
禁止从 `js` 文件中加载 `Vue` 组件。
|
|
63
67
|
|
|
@@ -112,7 +116,7 @@ import CComp from 'src/local-component/module/tip-match/tip-match-schedule-tree-
|
|
|
112
116
|
import DComp from 'src/local-component/module/tip-match/tip-match-schedule-tree-new/comp/d.vue';
|
|
113
117
|
```
|
|
114
118
|
|
|
115
|
-
###
|
|
119
|
+
### 4.2. no-plus-turn-number
|
|
116
120
|
|
|
117
121
|
禁止在 `vue` 的 `template` 中用 `+` 号转换字符串为数字
|
|
118
122
|
|
|
@@ -132,7 +136,7 @@ import DComp from 'src/local-component/module/tip-match/tip-match-schedule-tree-
|
|
|
132
136
|
/>
|
|
133
137
|
```
|
|
134
138
|
|
|
135
|
-
###
|
|
139
|
+
### 4.3. no-complex-key
|
|
136
140
|
|
|
137
141
|
不要在`vue`模板中使用复杂的`key`。包括:
|
|
138
142
|
|
|
@@ -172,7 +176,7 @@ getData() {
|
|
|
172
176
|
`uni-app`中,`key`重复的话,会造成挂载在组件上面的事件参数为`undefined`,从而不成功。
|
|
173
177
|
|
|
174
178
|
|
|
175
|
-
###
|
|
179
|
+
### 4.4. json-parse-try-catch
|
|
176
180
|
|
|
177
181
|
`JSON.parse` 应该加 `try catch`。
|
|
178
182
|
|
|
@@ -197,7 +201,7 @@ module.exports = {
|
|
|
197
201
|
}
|
|
198
202
|
```
|
|
199
203
|
|
|
200
|
-
###
|
|
204
|
+
### 4.5. no-import-all-in-one-api
|
|
201
205
|
|
|
202
206
|
使用 `src/api` 子仓库时, 不应该导入全部接口,而应该按需引入。
|
|
203
207
|
|
|
@@ -205,14 +209,14 @@ Bad case:
|
|
|
205
209
|
|
|
206
210
|
```js
|
|
207
211
|
// bad
|
|
208
|
-
import { pubg_fateClient } from 'src/api/git.
|
|
212
|
+
import { pubg_fateClient } from 'src/api/git.aow.com/itrpcprotocol/esport/esport_cgi/pubg_fate/pubg_fate.http';
|
|
209
213
|
```
|
|
210
214
|
|
|
211
215
|
Good case:
|
|
212
216
|
|
|
213
217
|
```js
|
|
214
218
|
// good
|
|
215
|
-
import { QueryGameListHomePageClient } from 'src/api/git.
|
|
219
|
+
import { QueryGameListHomePageClient } from 'src/api/git.aow.com/itrpcprotocol/esport/esport_cgi/pubg_fate/pubg_fate/QueryGameListHomePage.http';
|
|
216
220
|
```
|
|
217
221
|
|
|
218
222
|
Usage:
|
|
@@ -242,14 +246,14 @@ module.exports = {
|
|
|
242
246
|
rules: {
|
|
243
247
|
'light/no-import-all-in-one-api': [2, {
|
|
244
248
|
excludes: [
|
|
245
|
-
'src/api/git.
|
|
249
|
+
'src/api/git.aow.com/itrpcprotocol/esport/esport_cgi/pubg_fate/pubg_fate.http',
|
|
246
250
|
]
|
|
247
251
|
}],
|
|
248
252
|
},
|
|
249
253
|
}
|
|
250
254
|
```
|
|
251
255
|
|
|
252
|
-
下面是一个案例,根据这个规则,对一个线上项目进行改造。仅仅改动了[几个文件的几行引入语句](https://git.
|
|
256
|
+
下面是一个案例,根据这个规则,对一个线上项目进行改造。仅仅改动了[几个文件的几行引入语句](https://git.aow.com/pmd-mobile/match/gp-next/commit/20e0050fe10ed767dcb5d77dca76a9b51c23820e),就减少了主包 `50KB`,效果立竿见影。
|
|
253
257
|
|
|
254
258
|
之前:
|
|
255
259
|
|
|
@@ -263,7 +267,7 @@ module.exports = {
|
|
|
263
267
|
|
|
264
268
|
<img src="https://mike-1255355338.cos.ap-guangzhou.myqcloud.com/article/2025/5/own_mike_rfMPwBYtZmhXrthT.png" width="600">
|
|
265
269
|
|
|
266
|
-
###
|
|
270
|
+
### 4.6. no-js-file
|
|
267
271
|
|
|
268
272
|
运行时文件不允许使用 `js/jsx`,只允许 `ts/tsx`。子工程的 `config.js` 会自动排除。
|
|
269
273
|
|
|
@@ -291,7 +295,7 @@ module.exports = {
|
|
|
291
295
|
| include | 检查的列表,`glob` 模式 | `['src/{project,local-component,local-logic}/**/*.{js,jsx}']` |
|
|
292
296
|
| exclude | 排除的列表,`glob` 模式 | `['src/project/*/config.js']` |
|
|
293
297
|
|
|
294
|
-
###
|
|
298
|
+
### 4.7. valid-file-name
|
|
295
299
|
|
|
296
300
|
文件命名格式只允许使用 [kebab-case](https://developer.mozilla.org/en-US/docs/Glossary/Kebab_case)。子工程的 `App.vue` 会自动排除。
|
|
297
301
|
|
|
@@ -321,7 +325,7 @@ module.exports = {
|
|
|
321
325
|
| include | 检查的列表,`glob` 模式 | `['src/**/*']` |
|
|
322
326
|
| exclude | 排除的列表,`glob` 模式 | `['src/project/*/App.vue']` |
|
|
323
327
|
|
|
324
|
-
###
|
|
328
|
+
### 4.8. no-multiple-script
|
|
325
329
|
|
|
326
330
|
禁止 Vue 文件中存在多个 `<script>`。
|
|
327
331
|
|
|
@@ -342,8 +346,7 @@ module.exports = {
|
|
|
342
346
|
|
|
343
347
|
<img src="https://mike-1255355338.cos.ap-guangzhou.myqcloud.com/article/2025/5/own_mike_w7ADssRftSYE6myr.png" width="900">
|
|
344
348
|
|
|
345
|
-
|
|
346
|
-
### 3.9. valid-spelling
|
|
349
|
+
### 4.9. valid-spelling
|
|
347
350
|
|
|
348
351
|
校验正确的拼写,比如不能用"帐号",要使用"账号",不能使用"登陆",要使用"登录"。
|
|
349
352
|
|
|
@@ -368,7 +371,7 @@ module.exports = {
|
|
|
368
371
|
| -------- | ------------------------ | -------------------------------- |
|
|
369
372
|
| spelling | 错误拼写和正确拼写的映射 | `{ 帐号: '账号', 登陆: '登录' }` |
|
|
370
373
|
|
|
371
|
-
###
|
|
374
|
+
### 4.10. valid-shaohou
|
|
372
375
|
|
|
373
376
|
校验正确的"稍候"和"稍后",稍候后面不加词,稍后后面需要加词,比如"请稍候/请稍后再试"。
|
|
374
377
|
|
|
@@ -387,7 +390,7 @@ module.exports = {
|
|
|
387
390
|
}
|
|
388
391
|
```
|
|
389
392
|
|
|
390
|
-
###
|
|
393
|
+
### 4.11. classname-per-line
|
|
391
394
|
|
|
392
395
|
限制 Vue 中每行只有`1`个CSS类名,可以配置阈值。
|
|
393
396
|
|
|
@@ -412,7 +415,7 @@ module.exports = {
|
|
|
412
415
|
| ------ | -------------------------------- | ------ |
|
|
413
416
|
| counts | 检查阈值,小于阈值时,可以在一行 | `3` |
|
|
414
417
|
|
|
415
|
-
###
|
|
418
|
+
### 4.12. img-v-lazy
|
|
416
419
|
|
|
417
420
|
强制 `img` 标签使用 `v-lazy` 而不是 `:src`,可用于 Vue 项目中。
|
|
418
421
|
|
|
@@ -431,11 +434,11 @@ module.exports = {
|
|
|
431
434
|
}
|
|
432
435
|
```
|
|
433
436
|
|
|
434
|
-
###
|
|
437
|
+
### 4.13. no-direct-img-src
|
|
435
438
|
|
|
436
439
|
在 `jsx/tsx` 中禁止直接使用 `img src`,必须使用封装的 [`CdnImage` 组件](https://novlan1.github.io/docs/press-pix/zh-CN/cdn-image.html),可用于 React 项目中。
|
|
437
440
|
|
|
438
|
-
与 [img-v-lazy 规则](#
|
|
441
|
+
与 [img-v-lazy 规则](#_4-12-img-v-lazy) 类似,都是为了防止直接使用 COS 图片,而不是 CDN 图片。
|
|
439
442
|
|
|
440
443
|
Usage:
|
|
441
444
|
|
|
@@ -463,7 +466,7 @@ module.exports = {
|
|
|
463
466
|
| ------------- | ---------------------- | ---------- |
|
|
464
467
|
| componentName | 提示词中的自定义组件名 | `CdnImage` |
|
|
465
468
|
|
|
466
|
-
###
|
|
469
|
+
### 4.14. no-todo-comment
|
|
467
470
|
|
|
468
471
|
不允许存在 TODO。可防止调试代码被意外带到线上。
|
|
469
472
|
|
|
@@ -488,6 +491,107 @@ module.exports = {
|
|
|
488
491
|
| ------- | ---------- | ------- |
|
|
489
492
|
| keyword | 检查关键词 | `TODO:` |
|
|
490
493
|
|
|
491
|
-
|
|
494
|
+
### 4.15. no-non-index-import
|
|
495
|
+
|
|
496
|
+
限制只能从 `pmd-*` 包的 `lib` 目录下的模块第一层 `index` 引入,禁止从非 `index` 文件引入。
|
|
497
|
+
|
|
498
|
+
目的是为了保证模块导入的规范性,避免直接导入包内的具体实现文件,便于包的维护和重构。
|
|
499
|
+
|
|
500
|
+
允许的导入格式:
|
|
501
|
+
|
|
502
|
+
```js
|
|
503
|
+
// ✅ 直接导入模块(隐式index)
|
|
504
|
+
import Toast from 'pmd-widget/lib/toast';
|
|
505
|
+
import EventBus from 'pmd-tools/lib/e-bus';
|
|
506
|
+
|
|
507
|
+
// ✅ 显式导入index文件
|
|
508
|
+
import Toast from 'pmd-widget/lib/toast/index';
|
|
509
|
+
import EventBus from 'pmd-tools/lib/e-bus/index';
|
|
510
|
+
|
|
511
|
+
// ✅ 导入目录(隐式index)
|
|
512
|
+
import * as Utils from 'pmd-tools/lib/utils/';
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
禁止的导入格式:
|
|
516
|
+
|
|
517
|
+
```js
|
|
518
|
+
// ❌ 直接导入非index文件
|
|
519
|
+
import ToastComponent from 'pmd-widget/lib/toast/Toast.vue';
|
|
520
|
+
import helper from 'pmd-tools/lib/utils/helper.js';
|
|
521
|
+
|
|
522
|
+
// ❌ 多级目录的非index文件
|
|
523
|
+
import DeepComponent from 'pmd-widget/lib/toast/components/Modal.vue';
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
Usage:
|
|
527
|
+
|
|
528
|
+
```js
|
|
529
|
+
// .eslintrc.js
|
|
530
|
+
|
|
531
|
+
module.exports = {
|
|
532
|
+
plugins: [
|
|
533
|
+
'light',
|
|
534
|
+
],
|
|
535
|
+
rules: {
|
|
536
|
+
'light/no-non-index-import': 2,
|
|
537
|
+
},
|
|
538
|
+
}
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
配置选项:
|
|
542
|
+
|
|
543
|
+
| 字段 | 说明 | 默认值 |
|
|
544
|
+
| ------- | ------------------------------ | ------- |
|
|
545
|
+
| exclude | 排除的导入路径前缀数组 | `[]` |
|
|
546
|
+
|
|
547
|
+
例如,排除特定包的检查:
|
|
548
|
+
|
|
549
|
+
```js
|
|
550
|
+
// .eslintrc.js
|
|
551
|
+
|
|
552
|
+
module.exports = {
|
|
553
|
+
plugins: [
|
|
554
|
+
'light',
|
|
555
|
+
],
|
|
556
|
+
rules: {
|
|
557
|
+
'light/no-non-index-import': [2, {
|
|
558
|
+
exclude: [
|
|
559
|
+
'pmd-special/lib',
|
|
560
|
+
]
|
|
561
|
+
}],
|
|
562
|
+
},
|
|
563
|
+
}
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
### 4.16. no-decimal-in-brackets
|
|
567
|
+
|
|
568
|
+
禁止在方括号类名中使用小数点。背景:
|
|
569
|
+
|
|
570
|
+
>小程序中不能使用 `pr-[.28rem]` 这种,可以使用 `pr-1.12`,同时在`tailwind.config.js` 中配置下 `theme.extend.padding = {1.12: '.28rem'}`。
|
|
571
|
+
>
|
|
572
|
+
>原因是`uni-app`会把`class`中的`[.`解析成`\[\`放到`wxss`中,导致编译错误。
|
|
573
|
+
|
|
574
|
+
Usage:
|
|
575
|
+
|
|
576
|
+
```js
|
|
577
|
+
// .eslintrc.js
|
|
578
|
+
|
|
579
|
+
module.exports = {
|
|
580
|
+
plugins: [
|
|
581
|
+
'light',
|
|
582
|
+
],
|
|
583
|
+
rules: {
|
|
584
|
+
'light/no-decimal-in-brackets': 2,
|
|
585
|
+
},
|
|
586
|
+
}
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
配置选项:
|
|
590
|
+
|
|
591
|
+
| 字段 | 说明 | 默认值 |
|
|
592
|
+
| ------ | -------- | ----------------------------------- |
|
|
593
|
+
| regexp | 匹配正则 | `/\[[^\](]*\.\d+[a-zA-Z]+[^\]]*\]/` |
|
|
594
|
+
|
|
595
|
+
## 5. 更新日志
|
|
492
596
|
|
|
493
597
|
[点此查看](./CHANGELOG.md)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const utils = require('eslint-plugin-vue/lib/utils');
|
|
2
|
+
const TEST_REGEX = /\[[^\](]*\.\d+[a-zA-Z]+[^\]]*\]/;
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
meta: {
|
|
7
|
+
type: 'problem',
|
|
8
|
+
docs: {
|
|
9
|
+
description: '禁止在方括号类名中使用小数点',
|
|
10
|
+
category: 'Best Practices',
|
|
11
|
+
recommended: true,
|
|
12
|
+
},
|
|
13
|
+
schema: [
|
|
14
|
+
{
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
regexp: {
|
|
18
|
+
type: 'object',
|
|
19
|
+
default: TEST_REGEX,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
additionalProperties: false,
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
create(context) {
|
|
27
|
+
const options = context.options[0] || {};
|
|
28
|
+
const regex = options.regexp ?? TEST_REGEX;
|
|
29
|
+
|
|
30
|
+
return utils.defineTemplateBodyVisitor(context, {
|
|
31
|
+
'VAttribute[key.name=\'class\']'(node) {
|
|
32
|
+
if (!node.value || node.value.type !== 'VLiteral') return;
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
const classValue = node.value.value.trim();
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
const classNames = classValue.split(/\s+/).filter(c => c.trim());
|
|
39
|
+
const errorList = classNames.filter(item => regex.test(item));
|
|
40
|
+
|
|
41
|
+
if (!errorList?.length) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
context.report({
|
|
46
|
+
node,
|
|
47
|
+
loc: node.value.loc,
|
|
48
|
+
message: `禁止在方括号类名中使用小数点: ${errorList.join(', ')}`,
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
meta: {
|
|
3
|
+
type: 'problem',
|
|
4
|
+
docs: {
|
|
5
|
+
description: '限制只能从目录第一层index引入,禁止从非index文件引入',
|
|
6
|
+
category: 'Best Practices',
|
|
7
|
+
recommended: true,
|
|
8
|
+
},
|
|
9
|
+
fixable: null,
|
|
10
|
+
schema: [
|
|
11
|
+
{
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
exclude: {
|
|
15
|
+
type: 'array',
|
|
16
|
+
items: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
additionalProperties: false,
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
create(context) {
|
|
27
|
+
const options = context.options?.[0] || {};
|
|
28
|
+
const exclude = options.exclude || [];
|
|
29
|
+
return {
|
|
30
|
+
ImportDeclaration(node) {
|
|
31
|
+
const importPath = node.source.value;
|
|
32
|
+
|
|
33
|
+
if (!importPath.startsWith('pmd-')) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 解析路径
|
|
38
|
+
const parsed = parseImportPath(importPath);
|
|
39
|
+
if (!parsed) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const foundExcludePrefix = exclude.find(item => importPath.startsWith(item));
|
|
44
|
+
if (foundExcludePrefix) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 检查是否是允许的导入模式
|
|
49
|
+
if (!isValidImport(parsed)) {
|
|
50
|
+
context.report({
|
|
51
|
+
node,
|
|
52
|
+
message: '只能从目录第一层index引入。允许格式: package/lib/module 或 package/lib/module/index,禁止: package/lib/module/non-index',
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
function parseImportPath(importPath) {
|
|
61
|
+
// 匹配 pmd-widget/lib/toast 或 pmd-tools/lib/time
|
|
62
|
+
const pattern = /^@tencent\/(pmd-(?:[\w-]+))\/lib\/(.+)/;
|
|
63
|
+
const match = importPath.match(pattern);
|
|
64
|
+
|
|
65
|
+
if (!match) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const packageName = match[1];
|
|
70
|
+
const remainingPath = match[2];
|
|
71
|
+
|
|
72
|
+
// 移除末尾的斜杠
|
|
73
|
+
const normalizedPath = remainingPath.endsWith('/')
|
|
74
|
+
? remainingPath.slice(0, -1)
|
|
75
|
+
: remainingPath;
|
|
76
|
+
|
|
77
|
+
// 分割路径
|
|
78
|
+
const parts = normalizedPath.split('/');
|
|
79
|
+
|
|
80
|
+
// 获取文件名
|
|
81
|
+
const lastPart = parts[parts.length - 1];
|
|
82
|
+
const isIndexFile = lastPart === 'index';
|
|
83
|
+
|
|
84
|
+
// 判断是否是目录(以斜杠结尾或最后一部分是index)
|
|
85
|
+
const isDirectory = importPath.endsWith('/') || isIndexFile;
|
|
86
|
+
|
|
87
|
+
// 获取真正的模块名
|
|
88
|
+
let moduleName = parts[0];
|
|
89
|
+
let subPath = '';
|
|
90
|
+
|
|
91
|
+
if (parts.length > 1 && parts[parts.length - 1] === 'index') {
|
|
92
|
+
// 如果是 package/lib/module/index 格式
|
|
93
|
+
moduleName = parts[0];
|
|
94
|
+
subPath = parts.slice(0, -1).join('/');
|
|
95
|
+
} else {
|
|
96
|
+
moduleName = parts[0];
|
|
97
|
+
subPath = normalizedPath;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
packageName,
|
|
102
|
+
libPath: remainingPath,
|
|
103
|
+
fullPath: normalizedPath,
|
|
104
|
+
moduleName,
|
|
105
|
+
fileName: lastPart,
|
|
106
|
+
isIndexFile,
|
|
107
|
+
isDirectory,
|
|
108
|
+
parts,
|
|
109
|
+
subPath,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function isValidImport(parsed) {
|
|
114
|
+
const { parts, fileName, isDirectory, isIndexFile } = parsed;
|
|
115
|
+
|
|
116
|
+
// 情况1: 直接导入模块根目录(隐式index)
|
|
117
|
+
// 如: pmd-widget/lib/toast
|
|
118
|
+
if (parts.length === 1) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 情况2: 导入目录(以斜杠结尾),隐式index
|
|
123
|
+
// 如: pmd-tools/lib/e-bus/
|
|
124
|
+
if (isDirectory && !isIndexFile) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 情况3: 显式导入index文件
|
|
129
|
+
// 如: pmd-widget/lib/toast/index
|
|
130
|
+
if (isIndexFile && parts.length === 2 && fileName === 'index') {
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// 情况4: 如果有多级目录,但最后一级是index,且总共只有两级
|
|
135
|
+
// 如: package/lib/module/index
|
|
136
|
+
if (parts.length === 2 && fileName === 'index') {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 其他情况都是不允许的
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const { RuleTester } = require('eslint');
|
|
2
|
+
|
|
3
|
+
const rule = require('../rules/no-decimal-in-brackets');
|
|
4
|
+
|
|
5
|
+
const ERROR_MESSAGE = '禁止在方括号类名中使用小数点';
|
|
6
|
+
const ruleTester = new RuleTester({
|
|
7
|
+
parser: require.resolve('vue-eslint-parser'),
|
|
8
|
+
parserOptions: {
|
|
9
|
+
ecmaVersion: 'latest',
|
|
10
|
+
sourceType: 'module',
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
ruleTester.run('no-decimal-in-brackets', rule, {
|
|
15
|
+
valid: [
|
|
16
|
+
'<template><div class="pl-[1rem]"></div></template>',
|
|
17
|
+
|
|
18
|
+
'<template><div class="pl-[0.1]"></div></template>', // 允许小数点后无字母
|
|
19
|
+
'<template><div class="bg-[red]"></div></template>', // 允许纯字母
|
|
20
|
+
'<template><div class="text-[24]"></div></template>', // 允许纯数字
|
|
21
|
+
|
|
22
|
+
'<template><div class="bg-[rgba(0,0,0,.5)]"></div></template>', // 允许函数中的小数点
|
|
23
|
+
'<template><div class="opacity-[.5]"></div></template>', // 允许小数点前无数字
|
|
24
|
+
],
|
|
25
|
+
invalid: [
|
|
26
|
+
{
|
|
27
|
+
code: '<template><div class=\'pl-[0.1rem]\'></div></template>',
|
|
28
|
+
errors: [{ message: `${ERROR_MESSAGE}: pl-[0.1rem]` }],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
code: '<template><div class=\'text-[0.1rem] pl-[22.1px]\'></div></template>',
|
|
32
|
+
errors: [{ message: `${ERROR_MESSAGE}: text-[0.1rem], pl-[22.1px]` }],
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const { RuleTester } = require('eslint');
|
|
2
|
+
|
|
3
|
+
const rule = require('../rules/no-non-index-import');
|
|
4
|
+
|
|
5
|
+
const ruleTester = new RuleTester({
|
|
6
|
+
parserOptions: {
|
|
7
|
+
ecmaVersion: 2015,
|
|
8
|
+
sourceType: 'module',
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
ruleTester.run('no-non-index-import', rule, {
|
|
13
|
+
valid: [
|
|
14
|
+
// 正确的导入方式
|
|
15
|
+
'import { Toast } from \'pmd-widget/lib/toast\';',
|
|
16
|
+
'import { Toast } from \'pmd-widget/lib/toast/index\';',
|
|
17
|
+
'import { timeStampFormat } from \'pmd-tools/lib/time\';',
|
|
18
|
+
'import { getGlobalEBus } from \'pmd-tools/lib/e-bus/\';',
|
|
19
|
+
'import { something } from \'pmd-widget/lib/button\';',
|
|
20
|
+
'import { something } from \'pmd-widget/lib/button/index\';',
|
|
21
|
+
|
|
22
|
+
// 不相关的导入应该被忽略
|
|
23
|
+
'import React from \'react\';',
|
|
24
|
+
'import { something } from \'./local-module\';',
|
|
25
|
+
'import { something } from \'../utils\';',
|
|
26
|
+
],
|
|
27
|
+
|
|
28
|
+
invalid: [
|
|
29
|
+
// 错误的导入方式
|
|
30
|
+
{
|
|
31
|
+
code: 'import { Toast } from \'pmd-widget/lib/toast/index-web\';',
|
|
32
|
+
errors: [{ message: '只能从目录第一层index引入。允许格式: package/lib/module 或 package/lib/module/index,禁止: package/lib/module/non-index' }],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
code: 'import { timeStampFormat } from \'pmd-tools/lib/time/index-web\';',
|
|
36
|
+
errors: [{ message: '只能从目录第一层index引入。允许格式: package/lib/module 或 package/lib/module/index,禁止: package/lib/module/non-index' }],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
code: 'import { getGlobalEBus } from \'pmd-tools/lib/e-bus/global\';',
|
|
40
|
+
errors: [{ message: '只能从目录第一层index引入。允许格式: package/lib/module 或 package/lib/module/index,禁止: package/lib/module/non-index' }],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
code: 'import { something } from \'pmd-widget/lib/toast/utils\';',
|
|
44
|
+
errors: [{ message: '只能从目录第一层index引入。允许格式: package/lib/module 或 package/lib/module/index,禁止: package/lib/module/non-index' }],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
code: 'import { something } from \'pmd-widget/lib/component/button\';',
|
|
48
|
+
errors: [{ message: '只能从目录第一层index引入。允许格式: package/lib/module 或 package/lib/module/index,禁止: package/lib/module/non-index' }],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
code: 'import { something } from \'pmd-widget/lib/component/button\';',
|
|
52
|
+
errors: [{ message: '只能从目录第一层index引入。允许格式: package/lib/module 或 package/lib/module/index,禁止: package/lib/module/non-index' }],
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-light",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.19",
|
|
4
4
|
"description": "Simple Eslint Plugin",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eslint",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"minimatch": "^10.0.1",
|
|
29
29
|
"requireindex": "^1.2.0",
|
|
30
|
-
"t-comm": "^
|
|
30
|
+
"t-comm": "^3.0.3"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@babel/core": "^7.18.9",
|
|
@@ -38,7 +38,8 @@
|
|
|
38
38
|
"eslint-plugin-eslint-plugin": "^4.0.1",
|
|
39
39
|
"eslint-plugin-node": "^11.1.0",
|
|
40
40
|
"mocha": "^9.1.3",
|
|
41
|
-
"standard-version": "^9.5.0"
|
|
41
|
+
"standard-version": "^9.5.0",
|
|
42
|
+
"vue-eslint-parser": "^9.4.3"
|
|
42
43
|
},
|
|
43
44
|
"peerDependencies": {
|
|
44
45
|
"@babel/eslint-parser": ">=6",
|
|
@@ -51,6 +52,7 @@
|
|
|
51
52
|
"build": "rm -rf lib && node script/build",
|
|
52
53
|
"bump": "node ../../script/monorepo/version-simple $PWD",
|
|
53
54
|
"changelog": "node ../../script/monorepo/changelog $PWD",
|
|
54
|
-
"release": "node ../../script/monorepo/release $PWD"
|
|
55
|
+
"release": "node ../../script/monorepo/release $PWD",
|
|
56
|
+
"test": "node ./src/test/index.js"
|
|
55
57
|
}
|
|
56
58
|
}
|