Skip to content

Commit 4dfdc27

Browse files
feat(eslint): add tsslint-eslint-update and improve defineRules JSDocs (#74)
1 parent 6acfec3 commit 4dfdc27

5 files changed

Lines changed: 103 additions & 35 deletions

File tree

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/usr/bin/env node
2+
3+
const path = require('path');
4+
const fs = require('fs');
5+
const nodeModulesDirs = [];
6+
7+
let dir = __dirname;
8+
9+
while (true) {
10+
const nodeModuleDir = path.join(dir, 'node_modules');
11+
if (fs.existsSync(nodeModuleDir)) {
12+
nodeModulesDirs.push(nodeModuleDir);
13+
}
14+
const parentDir = path.resolve(dir, '..');
15+
if (parentDir === dir) {
16+
break;
17+
}
18+
dir = parentDir;
19+
}
20+
21+
try {
22+
const { generate } = require('../lib/dtsGenerate.js');
23+
generate(nodeModulesDirs).then(({ dts, stats }) => {
24+
fs.writeFileSync(path.resolve(__dirname, '..', 'lib', 'types.d.ts'), dts);
25+
26+
const indexPath = path.resolve(__dirname, '..', 'index.d.ts');
27+
if (fs.existsSync(indexPath)) {
28+
let indexContent = fs.readFileSync(indexPath, 'utf8');
29+
const defineRulesIndex = indexContent.indexOf('export declare function defineRules');
30+
const jsDocEnd = indexContent.lastIndexOf('*/', defineRulesIndex) + 2;
31+
const jsDocStart = indexContent.lastIndexOf('/**', jsDocEnd);
32+
33+
if (jsDocStart !== -1 && jsDocEnd !== -1 && jsDocStart < defineRulesIndex) {
34+
const statsTable = [
35+
'| Plugin | Rules |',
36+
'| :--- | :--- |',
37+
...Object.entries(stats)
38+
.filter(([_, count]) => count > 0)
39+
.sort((a, b) => b[1] - a[1])
40+
.map(([name, count]) => `| <span>${name}</span> | ${count} |`),
41+
].join('\n * ');
42+
43+
const newJsDoc = `/**
44+
* Converts an ESLint rules configuration to TSSLint rules.
45+
*
46+
* ${statsTable}
47+
*
48+
* ---
49+
* If you have added new ESLint plugins, please run \`npx tsslint-eslint-update\` to update this list.
50+
*
51+
* ---
52+
*/`;
53+
indexContent = indexContent.slice(0, jsDocStart) + newJsDoc + indexContent.slice(jsDocEnd);
54+
fs.writeFileSync(indexPath, indexContent);
55+
}
56+
}
57+
});
58+
} catch (err) {
59+
console.error(err);
60+
}

packages/eslint/index.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,24 @@ export async function convertRules(
7676
/**
7777
* Converts an ESLint rules configuration to TSSLint rules.
7878
*
79-
* The type definitions are generated when `@tsslint/eslint` is installed.
80-
* If the type definitions become outdated, please run
81-
* `node node_modules/@tsslint/eslint/scripts/generateDts.js` to update them.
79+
* ---
80+
* ⚠️ **Type definitions not generated**
81+
*
82+
* Please add `@tsslint/eslint` to `pnpm.onlyBuiltDependencies` in your `package.json` to allow the postinstall script to run.
83+
*
84+
* ```json
85+
* {
86+
* "pnpm": {
87+
* "onlyBuiltDependencies": ["@tsslint/eslint"]
88+
* }
89+
* }
90+
* ```
91+
*
92+
* After that, run `pnpm install` again to generate type definitions.
93+
*
94+
* If the type definitions become outdated, please run `npx tsslint-eslint-update` to update them.
95+
*
96+
* ---
8297
*/
8398
export async function defineRules(
8499
config: { [K in keyof ESLintRulesConfig]: boolean | ESLintRulesConfig[K] },

packages/eslint/lib/dtsGenerate.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export async function generate(
2222

2323
const visited = new Set<string>();
2424
const defs = new Map<any, [string, string]>();
25+
const stats: Record<string, number> = {};
2526

2627
for (const nodeModulesDir of nodeModulesDirs) {
2728
const pkgs = readdirDirSync(nodeModulesDir);
@@ -37,12 +38,17 @@ export async function generate(
3738
plugin = plugin.default;
3839
}
3940
if (plugin.rules) {
41+
stats[pluginName] = 0;
4042
for (const ruleName in plugin.rules) {
4143
const rule = plugin.rules[ruleName];
4244
if (subPkg === 'eslint-plugin') {
43-
addRule(pkg, ruleName, rule);
45+
if (addRule(pkg, ruleName, rule)) {
46+
stats[pluginName]++;
47+
}
4448
} else {
45-
addRule(pkg, `${subPkg.slice('eslint-plugin-'.length)}/${ruleName}`, rule);
49+
if (addRule(pkg, `${subPkg.slice('eslint-plugin-'.length)}/${ruleName}`, rule)) {
50+
stats[pluginName]++;
51+
}
4652
}
4753
}
4854
}
@@ -56,20 +62,26 @@ export async function generate(
5662
}
5763
if (plugin.rules) {
5864
const scope = pkg.replace('eslint-plugin-', '');
65+
stats[pkg] = 0;
5966
for (const ruleName in plugin.rules) {
6067
const rule = plugin.rules[ruleName];
61-
addRule(scope, ruleName, rule);
68+
if (addRule(scope, ruleName, rule)) {
69+
stats[pkg]++;
70+
}
6271
}
6372
}
6473
}
6574
else if (pkg === 'eslint') {
6675
const rulesDir = path.join(nodeModulesDir, pkg, 'lib', 'rules');
6776
const ruleFiles = fs.readdirSync(rulesDir);
77+
stats['eslint'] = 0;
6878
for (const ruleFile of ruleFiles) {
6979
if (ruleFile.endsWith('.js')) {
7080
const ruleName = ruleFile.replace('.js', '');
7181
const rule = await loader(path.join(rulesDir, ruleFile));
72-
addRule(undefined, ruleName, rule);
82+
if (addRule(undefined, ruleName, rule)) {
83+
stats['eslint']++;
84+
}
7385
}
7486
}
7587
}
@@ -84,7 +96,7 @@ export async function generate(
8496
line(`type ${typeName} = ${typeString};`);
8597
}
8698

87-
return dts;
99+
return { dts, stats };
88100

89101
function addRule(scope: string | undefined, ruleName: string, rule: any) {
90102
let ruleKey: string;
@@ -95,7 +107,7 @@ export async function generate(
95107
}
96108

97109
if (visited.has(ruleKey)) {
98-
return;
110+
return false;
99111
}
100112
visited.add(ruleKey);
101113

@@ -138,6 +150,7 @@ export async function generate(
138150
} else {
139151
line(`'${ruleKey}'?: any[],`);
140152
}
153+
return true;
141154
}
142155

143156
function line(line: string) {

packages/eslint/package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@
44
"license": "MIT",
55
"files": [
66
"**/*.js",
7-
"**/*.d.ts"
7+
"**/*.d.ts",
8+
"bin"
89
],
10+
"bin": {
11+
"tsslint-eslint-update": "bin/tsslint-eslint-update.js"
12+
},
913
"repository": {
1014
"type": "git",
1115
"url": "https://github.com/johnsoncodehk/tsslint.git",
1216
"directory": "packages/eslint"
1317
},
1418
"scripts": {
15-
"postinstall": "node scripts/generateDts.js"
19+
"postinstall": "node bin/tsslint-eslint-update.js"
1620
},
1721
"devDependencies": {
1822
"@tsslint/types": "3.0.0-alpha.0",

packages/eslint/scripts/generateDts.js

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)