Skip to content

Commit 6d8ed14

Browse files
scagoodaladdin-add
andauthored
feat: typescript (jsdoc) checking and definition generation (#169)
* chore: add some low hanging fruit types * chore: small steps * chore: Simplify check-existence * fix: All types in the utils directory * fix(prefer-promises): missing TraceMap type * fix(hashbang): Add missing types * fix: Add types for "process-exit-as-throw" * chore: unifi TraceMap * feat: Types for lib/rules * Update tsconfig.json Co-authored-by: Sebastian Good <[email protected]> * ci: Add tsc compile on pack and test * ci: Export types in package.json * ci: run tests and linting once * chore: Remove all "{Object}" from "@typedef" * fix: Remove typecast infavour of union a discriminator check * chore: Remove more unneed casting * fix: Better types from JSON.parse * chore: 1 typedef per doc comment * fix: dont cast ErrnoException * feat: better "TraceMap" types * chore: Add comment for the "ts-expect-error" --------- Co-authored-by: 唯然 <[email protected]>
1 parent 5e82d7f commit 6d8ed14

File tree

133 files changed

+2801
-959
lines changed

Some content is hidden

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

133 files changed

+2801
-959
lines changed

.github/workflows/CI.yml

+5-7
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,9 @@ jobs:
2222
uses: actions/setup-node@v4
2323
with:
2424
node-version: 20.x
25-
- name: Install Packages
26-
run: npm install
27-
- name: Lint
28-
run: npm run -s lint
25+
- run: npm install
26+
- run: npm run -s lint
27+
- run: npm run -s test:types
2928

3029
test:
3130
name: Test
@@ -64,7 +63,6 @@ jobs:
6463
- name: Install Packages
6564
run: npm install
6665
- name: Install ESLint ${{ matrix.eslint }}
67-
run: |
68-
npm install --no-save --force eslint@${{ matrix.eslint }}
66+
run: npm install --no-save --force eslint@${{ matrix.eslint }}
6967
- name: Test
70-
run: npm run -s test:ci
68+
run: npm run -s test:tests

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@
55
/test.js
66
.eslintcache
77
.vscode
8-
.idea/
8+
.idea/
9+
10+
types/

lib/configs/_commons.js

+17-19
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
"use strict"
22

3-
module.exports = {
4-
commonRules: {
5-
"n/no-deprecated-api": "error",
6-
"n/no-extraneous-import": "error",
7-
"n/no-extraneous-require": "error",
8-
"n/no-exports-assign": "error",
9-
"n/no-missing-import": "error",
10-
"n/no-missing-require": "error",
11-
"n/no-process-exit": "error",
12-
"n/no-unpublished-bin": "error",
13-
"n/no-unpublished-import": "error",
14-
"n/no-unpublished-require": "error",
15-
"n/no-unsupported-features/es-builtins": "error",
16-
"n/no-unsupported-features/es-syntax": "error",
17-
"n/no-unsupported-features/node-builtins": "error",
18-
"n/process-exit-as-throw": "error",
19-
"n/hashbang": "error",
20-
},
21-
}
3+
module.exports.commonRules = /** @type {const} */ ({
4+
"n/no-deprecated-api": "error",
5+
"n/no-extraneous-import": "error",
6+
"n/no-extraneous-require": "error",
7+
"n/no-exports-assign": "error",
8+
"n/no-missing-import": "error",
9+
"n/no-missing-require": "error",
10+
"n/no-process-exit": "error",
11+
"n/no-unpublished-bin": "error",
12+
"n/no-unpublished-import": "error",
13+
"n/no-unpublished-require": "error",
14+
"n/no-unsupported-features/es-builtins": "error",
15+
"n/no-unsupported-features/es-syntax": "error",
16+
"n/no-unsupported-features/node-builtins": "error",
17+
"n/process-exit-as-throw": "error",
18+
"n/hashbang": "error",
19+
})

lib/configs/recommended-module.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
const globals = require("globals")
44
const { commonRules } = require("./_commons")
55

6-
// eslintrc config: https://eslint.org/docs/latest/use/configure/configuration-files
6+
/**
7+
* https://eslint.org/docs/latest/use/configure/configuration-files
8+
* @type {import('eslint').ESLint.ConfigData}
9+
*/
710
module.exports.eslintrc = {
811
env: {
912
node: true,
@@ -30,7 +33,10 @@ module.exports.eslintrc = {
3033
},
3134
}
3235

33-
// flat config: https://eslint.org/docs/latest/use/configure/configuration-files-new
36+
/**
37+
* https://eslint.org/docs/latest/use/configure/configuration-files-new
38+
* @type {import('eslint').Linter.FlatConfig}
39+
*/
3440
module.exports.flat = {
3541
languageOptions: {
3642
sourceType: "module",
@@ -39,5 +45,7 @@ module.exports.flat = {
3945
...module.exports.eslintrc.globals,
4046
},
4147
},
42-
rules: module.exports.eslintrc.rules,
48+
rules:
49+
/** @type {import('eslint').Linter.RulesRecord} */
50+
(module.exports.eslintrc.rules),
4351
}

lib/configs/recommended-script.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
const globals = require("globals")
44
const { commonRules } = require("./_commons")
55

6-
// eslintrc config: https://eslint.org/docs/latest/use/configure/configuration-files
6+
/**
7+
* https://eslint.org/docs/latest/use/configure/configuration-files
8+
* @type {import('eslint').ESLint.ConfigData}
9+
*/
710
module.exports.eslintrc = {
811
env: {
912
node: true,
@@ -27,7 +30,10 @@ module.exports.eslintrc = {
2730
},
2831
}
2932

30-
// https://eslint.org/docs/latest/use/configure/configuration-files-new
33+
/**
34+
* https://eslint.org/docs/latest/use/configure/configuration-files-new
35+
* @type {import('eslint').Linter.FlatConfig}
36+
*/
3137
module.exports.flat = {
3238
languageOptions: {
3339
sourceType: "commonjs",
@@ -36,5 +42,7 @@ module.exports.flat = {
3642
...module.exports.eslintrc.globals,
3743
},
3844
},
39-
rules: module.exports.eslintrc.rules,
45+
rules:
46+
/** @type {import('eslint').Linter.RulesRecord} */
47+
(module.exports.eslintrc.rules),
4048
}

lib/configs/recommended.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
"use strict"
22

3-
const getPackageJson = require("../util/get-package-json")
3+
const { getPackageJson } = require("../util/get-package-json")
44
const moduleConfig = require("./recommended-module")
55
const scriptConfig = require("./recommended-script")
66

77
const packageJson = getPackageJson()
8-
const isModule = (packageJson && packageJson.type) === "module"
8+
9+
const isModule =
10+
packageJson != null &&
11+
typeof packageJson === "object" &&
12+
"type" in packageJson &&
13+
packageJson.type === "module"
914
const recommendedConfig = isModule ? moduleConfig : scriptConfig
1015

16+
/**
17+
* https://eslint.org/docs/latest/use/configure/configuration-files
18+
* @type {import('eslint').ESLint.ConfigData}
19+
*/
1120
module.exports.eslintrc = {
1221
...recommendedConfig.eslintrc,
1322
overrides: [

lib/eslint-utils.d.ts

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
declare module "eslint-plugin-es-x" {
2+
export const rules: NonNullable<import('eslint').ESLint.Plugin["rules"]>;
3+
}
4+
5+
declare module "@eslint-community/eslint-utils" {
6+
import * as estree from 'estree';
7+
import * as eslint from 'eslint';
8+
9+
type Node = estree.Node | estree.Expression;
10+
11+
export const READ: unique symbol;
12+
export const CALL: unique symbol;
13+
export const CONSTRUCT: unique symbol;
14+
export const ESM: unique symbol;
15+
export class ReferenceTracker {
16+
constructor(globalScope: eslint.Scope.Scope, { mode, globalObjectNames, }?: {
17+
mode?: "legacy" | "strict" | undefined;
18+
globalObjectNames?: string[] | undefined;
19+
} | undefined);
20+
variableStack: eslint.Scope.Variable[];
21+
globalScope: eslint.Scope.Scope;
22+
mode: "legacy" | "strict";
23+
globalObjectNames: string[];
24+
iterateGlobalReferences<Info extends unknown>(traceMap: TraceMap<Info>): IterableIterator<Reference<Info>>;
25+
iterateCjsReferences<Info extends unknown>(traceMap: TraceMap<Info>): IterableIterator<Reference<Info>>;
26+
iterateEsmReferences<Info extends unknown>(traceMap: TraceMap<Info>): IterableIterator<Reference<Info>>;
27+
}
28+
export namespace ReferenceTracker {
29+
export { READ };
30+
export { CALL };
31+
export { CONSTRUCT };
32+
export { ESM };
33+
}
34+
type ReferenceType = typeof READ | typeof CALL | typeof CONSTRUCT;
35+
type TraceMap<Info extends unknown> = {
36+
[READ]?: Info;
37+
[CALL]?: Info;
38+
[CONSTRUCT]?: Info;
39+
[key: string]: TraceMap<Info>;
40+
}
41+
type RichNode = eslint.Rule.Node | Node;
42+
type Reference<Info extends unknown> = {
43+
node: RichNode;
44+
path: string[];
45+
type: ReferenceType;
46+
info: Info;
47+
};
48+
49+
export function findVariable(initialScope: eslint.Scope.Scope, nameOrNode: string | Node): eslint.Scope.Variable | null;
50+
51+
export function getFunctionHeadLocation(node: Extract<eslint.Rule.Node, {
52+
type: 'FunctionDeclaration' | 'FunctionExpression' | 'ArrowFunctionExpression';
53+
}>, sourceCode: eslint.SourceCode): eslint.AST.SourceLocation | null;
54+
55+
export function getFunctionNameWithKind(node: Extract<eslint.Rule.Node, {
56+
type: 'FunctionDeclaration' | 'FunctionExpression' | 'ArrowFunctionExpression';
57+
}>, sourceCode?: eslint.SourceCode | undefined): string;
58+
59+
export function getInnermostScope(initialScope: eslint.Scope.Scope, node: Node): eslint.Scope.Scope;
60+
61+
export function getPropertyName(node: Extract<Node, {
62+
type: 'MemberExpression' | 'Property' | 'MethodDefinition' | 'PropertyDefinition';
63+
}>, initialScope?: eslint.Scope.Scope | undefined): string | null;
64+
65+
export function getStaticValue(node: Node, initialScope?: eslint.Scope.Scope | null | undefined): {
66+
value: unknown;
67+
optional?: never;
68+
} | {
69+
value: undefined;
70+
optional?: true;
71+
} | null;
72+
73+
export function getStringIfConstant(node: Node, initialScope?: eslint.Scope.Scope | null | undefined): string | null;
74+
75+
export function hasSideEffect(node: eslint.Rule.Node, sourceCode: eslint.SourceCode, { considerGetters, considerImplicitTypeConversion }?: VisitOptions | undefined): boolean;
76+
type VisitOptions = {
77+
considerGetters?: boolean | undefined;
78+
considerImplicitTypeConversion?: boolean | undefined;
79+
};
80+
}

lib/index.js

+77-61
Original file line numberDiff line numberDiff line change
@@ -5,73 +5,89 @@ const esmConfig = require("./configs/recommended-module")
55
const cjsConfig = require("./configs/recommended-script")
66
const recommendedConfig = require("./configs/recommended")
77

8-
const rules = {
9-
"callback-return": require("./rules/callback-return"),
10-
"exports-style": require("./rules/exports-style"),
11-
"file-extension-in-import": require("./rules/file-extension-in-import"),
12-
"global-require": require("./rules/global-require"),
13-
"handle-callback-err": require("./rules/handle-callback-err"),
14-
"no-callback-literal": require("./rules/no-callback-literal"),
15-
"no-deprecated-api": require("./rules/no-deprecated-api"),
16-
"no-exports-assign": require("./rules/no-exports-assign"),
17-
"no-extraneous-import": require("./rules/no-extraneous-import"),
18-
"no-extraneous-require": require("./rules/no-extraneous-require"),
19-
"no-missing-import": require("./rules/no-missing-import"),
20-
"no-missing-require": require("./rules/no-missing-require"),
21-
"no-mixed-requires": require("./rules/no-mixed-requires"),
22-
"no-new-require": require("./rules/no-new-require"),
23-
"no-path-concat": require("./rules/no-path-concat"),
24-
"no-process-env": require("./rules/no-process-env"),
25-
"no-process-exit": require("./rules/no-process-exit"),
26-
"no-restricted-import": require("./rules/no-restricted-import"),
27-
"no-restricted-require": require("./rules/no-restricted-require"),
28-
"no-sync": require("./rules/no-sync"),
29-
"no-unpublished-bin": require("./rules/no-unpublished-bin"),
30-
"no-unpublished-import": require("./rules/no-unpublished-import"),
31-
"no-unpublished-require": require("./rules/no-unpublished-require"),
32-
"no-unsupported-features/es-builtins": require("./rules/no-unsupported-features/es-builtins"),
33-
"no-unsupported-features/es-syntax": require("./rules/no-unsupported-features/es-syntax"),
34-
"no-unsupported-features/node-builtins": require("./rules/no-unsupported-features/node-builtins"),
35-
"prefer-global/buffer": require("./rules/prefer-global/buffer"),
36-
"prefer-global/console": require("./rules/prefer-global/console"),
37-
"prefer-global/process": require("./rules/prefer-global/process"),
38-
"prefer-global/text-decoder": require("./rules/prefer-global/text-decoder"),
39-
"prefer-global/text-encoder": require("./rules/prefer-global/text-encoder"),
40-
"prefer-global/url-search-params": require("./rules/prefer-global/url-search-params"),
41-
"prefer-global/url": require("./rules/prefer-global/url"),
42-
"prefer-node-protocol": require("./rules/prefer-node-protocol"),
43-
"prefer-promises/dns": require("./rules/prefer-promises/dns"),
44-
"prefer-promises/fs": require("./rules/prefer-promises/fs"),
45-
"process-exit-as-throw": require("./rules/process-exit-as-throw"),
46-
hashbang: require("./rules/hashbang"),
8+
/**
9+
* @typedef {{
10+
'recommended-module': import('eslint').ESLint.ConfigData;
11+
'recommended-script': import('eslint').ESLint.ConfigData;
12+
'recommended': import('eslint').ESLint.ConfigData;
13+
'flat/recommended-module': import('eslint').Linter.FlatConfig;
14+
'flat/recommended-script': import('eslint').Linter.FlatConfig;
15+
'flat/recommended': import('eslint').Linter.FlatConfig;
16+
'flat/mixed-esm-and-cjs': import('eslint').Linter.FlatConfig[];
17+
}} Configs
18+
*/
4719

48-
// Deprecated rules.
49-
"no-hide-core-modules": require("./rules/no-hide-core-modules"),
50-
shebang: require("./rules/shebang"),
51-
}
52-
53-
const mod = {
20+
/** @type {import('eslint').ESLint.Plugin & { configs: Configs }} */
21+
const plugin = {
5422
meta: {
5523
name: pkg.name,
5624
version: pkg.version,
5725
},
58-
rules,
26+
rules: /** @type {Record<string, import('eslint').Rule.RuleModule>} */ ({
27+
"callback-return": require("./rules/callback-return"),
28+
"exports-style": require("./rules/exports-style"),
29+
"file-extension-in-import": require("./rules/file-extension-in-import"),
30+
"global-require": require("./rules/global-require"),
31+
"handle-callback-err": require("./rules/handle-callback-err"),
32+
"no-callback-literal": require("./rules/no-callback-literal"),
33+
"no-deprecated-api": require("./rules/no-deprecated-api"),
34+
"no-exports-assign": require("./rules/no-exports-assign"),
35+
"no-extraneous-import": require("./rules/no-extraneous-import"),
36+
"no-extraneous-require": require("./rules/no-extraneous-require"),
37+
"no-missing-import": require("./rules/no-missing-import"),
38+
"no-missing-require": require("./rules/no-missing-require"),
39+
"no-mixed-requires": require("./rules/no-mixed-requires"),
40+
"no-new-require": require("./rules/no-new-require"),
41+
"no-path-concat": require("./rules/no-path-concat"),
42+
"no-process-env": require("./rules/no-process-env"),
43+
"no-process-exit": require("./rules/no-process-exit"),
44+
"no-restricted-import": require("./rules/no-restricted-import"),
45+
"no-restricted-require": require("./rules/no-restricted-require"),
46+
"no-sync": require("./rules/no-sync"),
47+
"no-unpublished-bin": require("./rules/no-unpublished-bin"),
48+
"no-unpublished-import": require("./rules/no-unpublished-import"),
49+
"no-unpublished-require": require("./rules/no-unpublished-require"),
50+
"no-unsupported-features/es-builtins": require("./rules/no-unsupported-features/es-builtins"),
51+
"no-unsupported-features/es-syntax": require("./rules/no-unsupported-features/es-syntax"),
52+
"no-unsupported-features/node-builtins": require("./rules/no-unsupported-features/node-builtins"),
53+
"prefer-global/buffer": require("./rules/prefer-global/buffer"),
54+
"prefer-global/console": require("./rules/prefer-global/console"),
55+
"prefer-global/process": require("./rules/prefer-global/process"),
56+
"prefer-global/text-decoder": require("./rules/prefer-global/text-decoder"),
57+
"prefer-global/text-encoder": require("./rules/prefer-global/text-encoder"),
58+
"prefer-global/url-search-params": require("./rules/prefer-global/url-search-params"),
59+
"prefer-global/url": require("./rules/prefer-global/url"),
60+
"prefer-node-protocol": require("./rules/prefer-node-protocol"),
61+
"prefer-promises/dns": require("./rules/prefer-promises/dns"),
62+
"prefer-promises/fs": require("./rules/prefer-promises/fs"),
63+
"process-exit-as-throw": require("./rules/process-exit-as-throw"),
64+
hashbang: require("./rules/hashbang"),
65+
66+
// Deprecated rules.
67+
"no-hide-core-modules": require("./rules/no-hide-core-modules"),
68+
shebang: require("./rules/shebang"),
69+
}),
70+
configs: {
71+
"recommended-module": { plugins: ["n"], ...esmConfig.eslintrc },
72+
"recommended-script": { plugins: ["n"], ...cjsConfig.eslintrc },
73+
recommended: { plugins: ["n"], ...recommendedConfig.eslintrc },
74+
"flat/recommended-module": { ...esmConfig.flat },
75+
"flat/recommended-script": { ...cjsConfig.flat },
76+
"flat/recommended": { ...recommendedConfig.flat },
77+
"flat/mixed-esm-and-cjs": [
78+
{ files: ["**/*.js"], ...recommendedConfig.flat },
79+
{ files: ["**/*.mjs"], ...esmConfig.flat },
80+
{ files: ["**/*.cjs"], ...cjsConfig.flat },
81+
],
82+
},
5983
}
6084

61-
// set configs, e.g. mod.configs["recommended-module"]
62-
// do not defined in the mod obj - to avoid circular dependency
63-
mod.configs = {
64-
"recommended-module": { plugins: ["n"], ...esmConfig.eslintrc },
65-
"recommended-script": { plugins: ["n"], ...cjsConfig.eslintrc },
66-
recommended: { plugins: ["n"], ...recommendedConfig.eslintrc },
67-
"flat/recommended-module": { plugins: { n: mod }, ...esmConfig.flat },
68-
"flat/recommended-script": { plugins: { n: mod }, ...cjsConfig.flat },
69-
"flat/recommended": { plugins: { n: mod }, ...recommendedConfig.flat },
70-
"flat/mixed-esm-and-cjs": [
71-
{ plugins: { n: mod }, files: ["**/*.js"], ...recommendedConfig.flat },
72-
{ plugins: { n: mod }, files: ["**/*.mjs"], ...esmConfig.flat },
73-
{ plugins: { n: mod }, files: ["**/*.cjs"], ...cjsConfig.flat },
74-
],
85+
plugin.configs["flat/recommended-module"].plugins = { n: plugin }
86+
plugin.configs["flat/recommended-script"].plugins = { n: plugin }
87+
plugin.configs["flat/recommended"].plugins = { n: plugin }
88+
89+
for (const config of plugin.configs["flat/mixed-esm-and-cjs"]) {
90+
config.plugins = { n: plugin }
7591
}
7692

77-
module.exports = mod
93+
module.exports = plugin

0 commit comments

Comments
 (0)