Skip to content

Commit 6ed426e

Browse files
authored
feat: use oxlint (#35)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Chores** - Standardized repository workflows and tooling configurations. - **Style / Refactor** - Enhanced code consistency, improved error handling, and updated type usage. - **Documentation** - Reorganized project documentation for clearer presentation in multiple languages. - **Tests** - Introduced new tests to verify core functionality exports. - Improved type safety and readability in existing tests. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 429f78c commit 6ed426e

File tree

49 files changed

+805
-259
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+805
-259
lines changed

.github/workflows/nodejs.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: CI
22

33
on:
44
push:
5-
branches: [ master ]
5+
branches: [master]
66
pull_request:
7-
branches: [ master ]
7+
branches: [master]
88

99
jobs:
1010
Job:

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: Release
22
on:
33
push:
4-
branches: [ master ]
4+
branches: [master]
55

66
jobs:
77
release:

.husky/pre-commit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
npx lint-staged

.oxlintrc.json

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
{
2+
"$schema": "./node_modules/oxlint/configuration_schema.json",
3+
"env": {
4+
"node": true,
5+
"mocha": true
6+
},
7+
"categories": {
8+
"correctness": "error",
9+
"perf": "error",
10+
"nursery": "error",
11+
"restriction": "error",
12+
"style": "error",
13+
"pedantic": "error",
14+
"suspicious": "error"
15+
},
16+
"plugins": [
17+
"import",
18+
"typescript",
19+
"unicorn",
20+
"jsdoc",
21+
"node",
22+
"promise",
23+
"oxc"
24+
],
25+
"rules": {
26+
// eslint
27+
"constructor-super": "error",
28+
"getter-return": "error",
29+
"no-undef": "error",
30+
"no-unreachable": "error",
31+
"no-var": "error",
32+
"no-eq-null": "error",
33+
"no-await-in-loop": "allow",
34+
"eqeqeq": ["error", "smart"],
35+
"init-declarations": "allow",
36+
"curly": "allow",
37+
"no-ternary": "allow",
38+
"max-params": ["error", 5],
39+
"no-await-expression-member": "error",
40+
"no-continue": "allow",
41+
"guard-for-in": "allow",
42+
"func-style": "allow",
43+
"sort-imports": "allow",
44+
"yoda": "allow",
45+
"sort-keys": "allow",
46+
"no-magic-numbers": "allow",
47+
"no-duplicate-imports": "error",
48+
"no-multi-assign": "error",
49+
"func-names": "error",
50+
"default-param-last": "error",
51+
"prefer-object-spread": "error",
52+
"no-undefined": "allow",
53+
"no-plusplus": "allow",
54+
// maybe warn
55+
"no-console": "warn",
56+
"no-extraneous-class": "allow",
57+
"no-empty-function": "allow",
58+
"max-depth": ["error", 6],
59+
"max-lines-per-function": "allow",
60+
"no-lonely-if": "error",
61+
"max-lines": "allow",
62+
"require-await": "allow",
63+
"max-nested-callbacks": ["error", 5],
64+
"max-classes-per-file": "allow",
65+
"radix": "allow",
66+
"no-negated-condition": "error",
67+
"no-else-return": "error",
68+
"no-throw-literal": "error",
69+
70+
// import
71+
"import/exports-last": "allow",
72+
"import/max-dependencies": "allow",
73+
"import/no-cycle": "error",
74+
"import/no-anonymous-default-export": "allow",
75+
"import/no-namespace": "error",
76+
"import/named": "error",
77+
"import/export": "allow",
78+
"import/no-default-export": "allow",
79+
"import/unambiguous": "error",
80+
81+
// promise
82+
"promise/no-return-wrap": "error",
83+
"promise/param-names": "error",
84+
"promise/prefer-await-to-callbacks": "error",
85+
"promise/prefer-await-to-then": "error",
86+
"promise/prefer-catch": "error",
87+
"promise/no-return-in-finally": "error",
88+
"promise/avoid-new": "error",
89+
90+
// unicorn
91+
"unicorn/error-message": "error",
92+
"unicorn/no-null": "allow",
93+
"unicorn/filename-case": "allow",
94+
"unicorn/prefer-structured-clone": "error",
95+
"unicorn/prefer-logical-operator-over-ternary": "error",
96+
"unicorn/prefer-number-properties": "error",
97+
"unicorn/prefer-array-some": "error",
98+
"unicorn/prefer-string-slice": "error",
99+
// "unicorn/no-null": "error",
100+
"unicorn/throw-new-error": "error",
101+
"unicorn/catch-error-name": "allow",
102+
"unicorn/prefer-spread": "allow",
103+
"unicorn/numeric-separators-style": "error",
104+
"unicorn/prefer-string-raw": "error",
105+
"unicorn/text-encoding-identifier-case": "error",
106+
"unicorn/no-array-for-each": "error",
107+
"unicorn/explicit-length-check": "error",
108+
"unicorn/no-lonely-if": "error",
109+
"unicorn/no-useless-undefined": "allow",
110+
"unicorn/prefer-date-now": "error",
111+
"unicorn/no-static-only-class": "allow",
112+
"unicorn/no-typeof-undefined": "error",
113+
"unicorn/prefer-negative-index": "error",
114+
"unicorn/no-anonymous-default-export": "allow",
115+
116+
// oxc
117+
"oxc/no-map-spread": "error",
118+
"oxc/no-rest-spread-properties": "allow",
119+
"oxc/no-optional-chaining": "allow",
120+
"oxc/no-async-await": "allow",
121+
122+
// typescript
123+
"typescript/explicit-function-return-type": "allow",
124+
"typescript/consistent-type-imports": "error",
125+
"typescript/consistent-type-definitions": "error",
126+
"typescript/consistent-indexed-object-style": "allow",
127+
"typescript/no-inferrable-types": "error",
128+
"typescript/array-type": "error",
129+
"typescript/no-non-null-assertion": "error",
130+
"typescript/no-explicit-any": "error",
131+
"typescript/no-import-type-side-effects": "error",
132+
"typescript/no-dynamic-delete": "error",
133+
"typescript/prefer-ts-expect-error": "error",
134+
"typescript/ban-ts-comment": "error",
135+
"typescript/prefer-enum-initializers": "error",
136+
137+
// jsdoc
138+
"jsdoc/require-returns": "allow",
139+
"jsdoc/require-param": "allow"
140+
},
141+
"overrides": [
142+
{
143+
"files": ["test/**/*.ts"],
144+
"rules": {
145+
"no-console": "allow",
146+
"promise/prefer-await-to-callbacks": "allow"
147+
}
148+
}
149+
],
150+
"ignorePatterns": ["index.d.ts", "test/fixtures/**", "__snapshots__"]
151+
}

.prettierignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
CHANGELOG.md
2+
__snapshots__

.prettierrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"singleQuote": true,
3+
"trailingComma": "es5",
4+
"tabWidth": 2,
5+
"arrowParens": "avoid"
6+
}

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ exports.logrotator = {
3737
```js
3838
// if any files need rotate by file size, config here
3939
exports.logrotator = {
40-
filesRotateByHour: [], // list of files that will be rotated by hour
41-
hourDelimiter: '-', // rotate the file by hour use specified delimiter
42-
filesRotateBySize: [], // list of files that will be rotated by size
43-
maxFileSize: 50 * 1024 * 1024, // Max file size to judge if any file need rotate
44-
maxFiles: 10, // pieces rotate by size
45-
rotateDuration: 60000, // time interval to judge if any file need rotate
46-
maxDays: 31, // keep max days log files, default is `31`. Set `0` to keep all logs
47-
gzip:false, // use gzip compress logger on rotate file, default is `false`. Set `true` to enable
40+
filesRotateByHour: [], // list of files that will be rotated by hour
41+
hourDelimiter: '-', // rotate the file by hour use specified delimiter
42+
filesRotateBySize: [], // list of files that will be rotated by size
43+
maxFileSize: 50 * 1024 * 1024, // Max file size to judge if any file need rotate
44+
maxFiles: 10, // pieces rotate by size
45+
rotateDuration: 60000, // time interval to judge if any file need rotate
46+
maxDays: 31, // keep max days log files, default is `31`. Set `0` to keep all logs
47+
gzip: false, // use gzip compress logger on rotate file, default is `false`. Set `true` to enable
4848
};
4949
```
5050

@@ -86,7 +86,7 @@ module.exports = app => {
8686
},
8787
async task() {
8888
await rotator.rotate();
89-
}
89+
},
9090
};
9191
};
9292

README.zh-CN.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ exports.logrotator = true;
2828
```js
2929
// 如果有需要按照文件大小切割的日志,在这里配置
3030
exports.logrotator = {
31-
filesRotateByHour: [], // 需要按小时切割的文件
32-
hourDelimiter: '-', // 按照小时切割的文件, 小时部分的分隔符.
33-
filesRotateBySize: [], // 需要按大小切割的文件,其他日志文件仍按照通常方式切割
34-
maxFileSize: 50 * 1024 * 1024, // 最大文件大小,默认为50m
35-
maxFiles: 10, // 按大小切割时,文件最大切割的份数
36-
rotateDuration: 60000, // 按大小切割时,文件扫描的间隔时间
37-
maxDays: 31, // 日志保留最久天数
31+
filesRotateByHour: [], // 需要按小时切割的文件
32+
hourDelimiter: '-', // 按照小时切割的文件, 小时部分的分隔符.
33+
filesRotateBySize: [], // 需要按大小切割的文件,其他日志文件仍按照通常方式切割
34+
maxFileSize: 50 * 1024 * 1024, // 最大文件大小,默认为50m
35+
maxFiles: 10, // 按大小切割时,文件最大切割的份数
36+
rotateDuration: 60000, // 按大小切割时,文件扫描的间隔时间
37+
maxDays: 31, // 日志保留最久天数
3838
};
3939
```
4040

@@ -74,9 +74,9 @@ module.exports = app => {
7474
type: 'worker', // only one worker run this task
7575
cron: '10 * * * *', // custom cron, or use interval
7676
},
77-
* task() {
77+
*task() {
7878
yield rotator.rotate();
79-
}
79+
},
8080
};
8181
};
8282

@@ -86,7 +86,7 @@ function getRotator(app) {
8686
// LogRotator will rename srcPath to targetPath
8787
// 返回一个 map,其中包含 srcPath 和 targetPath,
8888
// LogRotator 会将 srcPath 重命名成 targetPath
89-
* getRotateFiles() {
89+
*getRotateFiles() {
9090
const files = new Map();
9191
const srcPath = '/home/admin/foo.log';
9292
const targetPath = '/home/admin/foo.log.2016.09.30';

package.json

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,18 @@
4242
"utility": "^2.5.0"
4343
},
4444
"devDependencies": {
45-
"@arethetypeswrong/cli": "^0.17.3",
45+
"@arethetypeswrong/cli": "^0.17.4",
4646
"@eggjs/bin": "7",
47-
"@eggjs/mock": "^6.0.5",
47+
"@eggjs/mock": "^6.0.6",
4848
"@eggjs/tsconfig": "1",
4949
"@types/mocha": "10",
5050
"@types/node": "22",
5151
"egg": "^4.0.5",
5252
"egg-logger": "^3.6.1",
53-
"eslint": "8",
54-
"eslint-config-egg": "14",
53+
"husky": "9",
54+
"lint-staged": "15",
55+
"oxlint": "^0.16.2",
56+
"prettier": "3",
5557
"glob": "^11.0.1",
5658
"rimraf": "6",
5759
"snap-shot-it": "^7.9.10",
@@ -61,15 +63,23 @@
6163
"typescript": "5"
6264
},
6365
"scripts": {
64-
"lint": "eslint --cache src test --ext .ts",
66+
"lint": "oxlint",
6567
"pretest": "npm run clean && npm run lint -- --fix",
6668
"test": "egg-bin test",
6769
"test:snapshot:update": "SNAPSHOT_UPDATE=1 egg-bin test",
6870
"preci": "npm run clean && npm run lint",
6971
"ci": "egg-bin cov",
7072
"postci": "npm run prepublishOnly && npm run clean",
7173
"clean": "rimraf dist",
72-
"prepublishOnly": "tshy && tshy-after && attw --pack"
74+
"prepublishOnly": "tshy && tshy-after && attw --pack",
75+
"prepare": "husky"
76+
},
77+
"lint-staged": {
78+
"*": "prettier --write --ignore-unknown --cache",
79+
"*.{ts,js,json,md,yml}": [
80+
"prettier --ignore-unknown --write",
81+
"oxlint --fix"
82+
]
7383
},
7484
"type": "module",
7585
"tshy": {

src/app/schedule/clean_log.ts

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import path from 'node:path';
22
import fs from 'node:fs/promises';
3+
34
import { exists } from 'utility';
45
import moment from 'moment';
5-
import { EggCore } from '@eggjs/core';
6+
import type { EggCore } from '@eggjs/core';
7+
68
import { walkLoggerFile } from '../../lib/utils.js';
79

810
// clean all xxx.log.YYYY-MM-DD before expired date.
@@ -16,14 +18,16 @@ export default (app: EggCore) => ({
1618
const logger = app.coreLogger;
1719
const logDirs = new Set<string>();
1820
const loggerFiles = walkLoggerFile(app.loggers);
19-
loggerFiles.forEach(file => {
21+
for (const file of loggerFiles) {
2022
const logDir = path.dirname(file);
2123
logDirs.add(logDir);
22-
});
24+
}
2325
const maxDays = app.config.logrotator.maxDays;
2426
if (maxDays && maxDays > 0) {
2527
try {
26-
const tasks = Array.from(logDirs, logDir => removeExpiredLogFiles(logDir, maxDays, logger));
28+
const tasks = Array.from(logDirs, logDir =>
29+
removeExpiredLogFiles(logDir, maxDays, logger)
30+
);
2731
await Promise.all(tasks);
2832
} catch (err) {
2933
logger.error(err);
@@ -35,7 +39,11 @@ export default (app: EggCore) => ({
3539
});
3640

3741
// remove expired log files: xxx.log.YYYY-MM-DD
38-
async function removeExpiredLogFiles(logDir: string, maxDays: number, logger: EggCore['coreLogger']) {
42+
async function removeExpiredLogFiles(
43+
logDir: string,
44+
maxDays: number,
45+
logger: EggCore['coreLogger']
46+
) {
3947
// ignore not exists dir
4048
const stat = await exists(logDir);
4149
if (!stat) {
@@ -46,8 +54,8 @@ async function removeExpiredLogFiles(logDir: string, maxDays: number, logger: Eg
4654
const files = await fs.readdir(logDir);
4755
const expiredDate = moment().subtract(maxDays, 'days').startOf('date');
4856
const names = files.filter(file => {
49-
const name = path.extname(file).substring(1);
50-
if (!/^\d{4}\-\d{2}\-\d{2}/.test(name)) {
57+
const name = path.extname(file).slice(1);
58+
if (!/^\d{4}-\d{2}-\d{2}/.test(name)) {
5159
return false;
5260
}
5361
const date = moment(name, 'YYYY-MM-DD').startOf('date');
@@ -60,15 +68,20 @@ async function removeExpiredLogFiles(logDir: string, maxDays: number, logger: Eg
6068
return;
6169
}
6270

63-
logger.info(`[@eggjs/logrotator] start remove ${logDir} files: ${names.join(', ')}`);
71+
logger.info(
72+
`[@eggjs/logrotator] start remove ${logDir} files: ${names.join(', ')}`
73+
);
6474

65-
await Promise.all(names.map(async name => {
66-
const logFile = path.join(logDir, name);
67-
try {
68-
await fs.unlink(logFile);
69-
} catch (err: any) {
70-
err.message = `[@eggjs/logrotator] remove logFile ${logFile} error, ${err.message}`;
71-
logger.error(err);
72-
}
73-
}));
75+
await Promise.all(
76+
names.map(async name => {
77+
const logFile = path.join(logDir, name);
78+
try {
79+
await fs.unlink(logFile);
80+
} catch (e) {
81+
const err = e as Error;
82+
err.message = `[@eggjs/logrotator] remove logFile ${logFile} error, ${err.message}`;
83+
logger.error(err);
84+
}
85+
})
86+
);
7487
}

0 commit comments

Comments
 (0)