-
-
Notifications
You must be signed in to change notification settings - Fork 169
Expand file tree
/
Copy pathimportsAsDependencies.js
More file actions
131 lines (117 loc) · 2.95 KB
/
importsAsDependencies.js
File metadata and controls
131 lines (117 loc) · 2.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import iterateJsdoc from '../iterateJsdoc.js';
import {
parse,
traverse,
tryParse,
} from '@es-joy/jsdoccomment';
import {
readFileSync,
} from 'fs';
import {
isBuiltin as isBuiltinModule,
} from 'node:module';
import {
join,
} from 'path';
/**
* @type {Set<string>|null}
*/
let deps;
const setDeps = function () {
try {
const pkg = JSON.parse(
readFileSync(join(process.cwd(), './package.json'), 'utf8'),
);
deps = new Set([
...(pkg.dependencies ?
/* c8 ignore next 2 */
Object.keys(pkg.dependencies) :
[]),
...(pkg.devDependencies ?
/* c8 ignore next 2 */
Object.keys(pkg.devDependencies) :
[]),
]);
/* c8 ignore next -- our package.json exists */
} catch (error) {
/* c8 ignore next -- our package.json exists */
deps = null;
/* c8 ignore next 4 -- our package.json exists */
/* eslint-disable no-console -- Inform user */
console.log(error);
/* eslint-enable no-console -- Inform user */
}
};
const moduleCheck = new Map();
export default iterateJsdoc(({
jsdoc,
settings,
utils,
}) => {
if (deps === undefined) {
setDeps();
}
/* c8 ignore next 3 -- our package.json exists */
if (deps === null) {
return;
}
const {
mode,
} = settings;
for (const tag of jsdoc.tags) {
let typeAst;
try {
typeAst = mode === 'permissive' ? tryParse(tag.type) : parse(tag.type, mode);
} catch {
continue;
}
// eslint-disable-next-line no-loop-func -- Safe
traverse(typeAst, (nde) => {
/* c8 ignore next 3 -- TS guard */
if (deps === null) {
return;
}
if (nde.type === 'JsdocTypeImport') {
let mod = nde.element.value.replace(
/^(@[^\/]+\/[^\/]+|[^\/]+).*$/v, '$1',
);
if ((/^[.\/]/v).test(mod)) {
return;
}
if (isBuiltinModule(mod)) {
// mod = '@types/node';
// moduleCheck.set(mod, !deps.has(mod));
return;
} else if (!moduleCheck.has(mod)) {
let pkg;
try {
pkg = JSON.parse(
readFileSync(join(process.cwd(), 'node_modules', mod, './package.json'), 'utf8'),
);
} catch {
// Ignore
}
if (!pkg || (!pkg.types && !pkg.typings)) {
mod = `@types/${mod}`;
}
moduleCheck.set(mod, !deps.has(mod));
}
if (moduleCheck.get(mod)) {
utils.reportJSDoc(
'import points to package which is not found in dependencies',
tag,
);
}
}
});
}
}, {
iterateAllJsdocs: true,
meta: {
docs: {
description: 'Reports if JSDoc `import()` statements point to a package which is not listed in `dependencies` or `devDependencies`',
url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/imports-as-dependencies.md#repos-sticky-header',
},
type: 'suggestion',
},
});