eslint-plugin-light 1.0.18 → 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 CHANGED
@@ -1,3 +1,15 @@
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
+
1
13
  ## <small>1.0.18 (2025-08-08)</small>
2
14
 
3
15
  * feat(eslint): add no-decimal-in-brackets rule ([a4c2b0d](https://github.com/novlan1/plugin-light/commits/a4c2b0d))
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
- ## 2. 使用
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
- ## 3. 规则
62
+ ## 4. 规则
59
63
 
60
- ### 3.1. valid-vue-comp-import
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
- ### 3.2. no-plus-turn-number
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
- ### 3.3. no-complex-key
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
- ### 3.4. json-parse-try-catch
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
- ### 3.5. no-import-all-in-one-api
204
+ ### 4.5. no-import-all-in-one-api
201
205
 
202
206
  使用 `src/api` 子仓库时, 不应该导入全部接口,而应该按需引入。
203
207
 
@@ -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
- ### 3.6. no-js-file
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
- ### 3.7. valid-file-name
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
- ### 3.8. no-multiple-script
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
- ### 3.10. valid-shaohou
374
+ ### 4.10. valid-shaohou
372
375
 
373
376
  校验正确的"稍候"和"稍后",稍候后面不加词,稍后后面需要加词,比如"请稍候/请稍后再试"。
374
377
 
@@ -387,7 +390,7 @@ module.exports = {
387
390
  }
388
391
  ```
389
392
 
390
- ### 3.11. classname-per-line
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
- ### 3.12. img-v-lazy
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
- ### 3.13. no-direct-img-src
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 规则](#_3-12-img-v-lazy) 类似,都是为了防止直接使用 COS 图片,而不是 CDN 图片。
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
- ### 3.14. no-todo-comment
469
+ ### 4.14. no-todo-comment
467
470
 
468
471
  不允许存在 TODO。可防止调试代码被意外带到线上。
469
472
 
@@ -488,7 +491,79 @@ module.exports = {
488
491
  | ------- | ---------- | ------- |
489
492
  | keyword | 检查关键词 | `TODO:` |
490
493
 
491
- ### 3.15. no-decimal-in-brackets
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
492
567
 
493
568
  禁止在方括号类名中使用小数点。背景:
494
569
 
@@ -517,6 +592,6 @@ module.exports = {
517
592
  | ------ | -------- | ----------------------------------- |
518
593
  | regexp | 匹配正则 | `/\[[^\](]*\.\d+[a-zA-Z]+[^\]]*\]/` |
519
594
 
520
- ## 4. 更新日志
595
+ ## 5. 更新日志
521
596
 
522
597
  [点此查看](./CHANGELOG.md)
@@ -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,5 @@
1
+ require('./no-decimal-in-brackets');
2
+ require('./no-direct-img-src');
3
+ require('./no-non-index-import');
4
+
5
+ console.log('所有测试通过!');
@@ -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.18",
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": "^1.5.40"
30
+ "t-comm": "^3.0.3"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@babel/core": "^7.18.9",
@@ -52,6 +52,7 @@
52
52
  "build": "rm -rf lib && node script/build",
53
53
  "bump": "node ../../script/monorepo/version-simple $PWD",
54
54
  "changelog": "node ../../script/monorepo/changelog $PWD",
55
- "release": "node ../../script/monorepo/release $PWD"
55
+ "release": "node ../../script/monorepo/release $PWD",
56
+ "test": "node ./src/test/index.js"
56
57
  }
57
58
  }