eslint-plugin-stamhoofd 2.134.0 → 2.136.0
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/package.json +2 -2
- package/src/index.js +13 -0
- package/src/rules/no-package-self-import.js +104 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-stamhoofd",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.136.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -30,5 +30,5 @@
|
|
|
30
30
|
"publishConfig": {
|
|
31
31
|
"access": "public"
|
|
32
32
|
},
|
|
33
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "0adab3f0a2aac8470c58ac717c3d96a824e5f935"
|
|
34
34
|
}
|
package/src/index.js
CHANGED
|
@@ -13,11 +13,13 @@ import node from './configs/node.js';
|
|
|
13
13
|
import typescript from './configs/typescript.js';
|
|
14
14
|
import asyncComponentWithProperties from './rules/async-component-with-properties.js';
|
|
15
15
|
import asyncRouteComponents from './rules/async-route-components.js';
|
|
16
|
+
import noPackageSelfImport from './rules/no-package-self-import.js';
|
|
16
17
|
import preferDefineRoute from './rules/prefer-define-route.js';
|
|
17
18
|
|
|
18
19
|
const rules = {
|
|
19
20
|
'async-component-with-properties': asyncComponentWithProperties,
|
|
20
21
|
'async-route-components': asyncRouteComponents,
|
|
22
|
+
'no-package-self-import': noPackageSelfImport,
|
|
21
23
|
'prefer-define-route': preferDefineRoute,
|
|
22
24
|
};
|
|
23
25
|
const stamhoofdPlugin = {
|
|
@@ -72,6 +74,17 @@ const baseRules = [
|
|
|
72
74
|
'import/no-relative-packages': 'error',
|
|
73
75
|
},
|
|
74
76
|
},
|
|
77
|
+
{
|
|
78
|
+
plugins: {
|
|
79
|
+
stamhoofd: stamhoofdPlugin,
|
|
80
|
+
},
|
|
81
|
+
rules: {
|
|
82
|
+
// Importing a package's own name from inside that package resolves through its
|
|
83
|
+
// "exports" (the built dist for some packages), which duplicates modules and
|
|
84
|
+
// breaks tsc project references. Use a relative or '#' subpath import instead.
|
|
85
|
+
'stamhoofd/no-package-self-import': 'error',
|
|
86
|
+
},
|
|
87
|
+
},
|
|
75
88
|
|
|
76
89
|
stylistic.configs.customize({
|
|
77
90
|
// the following options are the default values
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
// Directory → name of the nearest package.json with a "name" field (null if none).
|
|
5
|
+
const packageNameCache = new Map();
|
|
6
|
+
|
|
7
|
+
function findOwnPackageName(startDir) {
|
|
8
|
+
const unresolvedDirs = [];
|
|
9
|
+
let dir = startDir;
|
|
10
|
+
let name = null;
|
|
11
|
+
|
|
12
|
+
while (true) {
|
|
13
|
+
if (packageNameCache.has(dir)) {
|
|
14
|
+
name = packageNameCache.get(dir);
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
unresolvedDirs.push(dir);
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const parsed = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
|
|
21
|
+
if (typeof parsed.name === 'string' && parsed.name !== '') {
|
|
22
|
+
name = parsed.name;
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
} catch {
|
|
26
|
+
// No (or invalid) package.json in this directory: keep walking up.
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const parent = path.dirname(dir);
|
|
30
|
+
if (parent === dir) {
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
dir = parent;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
for (const visited of unresolvedDirs) {
|
|
37
|
+
packageNameCache.set(visited, name);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return name;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getImportedPackageName(specifier) {
|
|
44
|
+
if (specifier.startsWith('.') || specifier.startsWith('/') || specifier.startsWith('#')) {
|
|
45
|
+
// Relative, absolute or subpath ("imports") specifiers never target a package by name.
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const parts = specifier.split('/');
|
|
50
|
+
if (specifier.startsWith('@')) {
|
|
51
|
+
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : null;
|
|
52
|
+
}
|
|
53
|
+
return parts[0];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default {
|
|
57
|
+
meta: {
|
|
58
|
+
type: 'problem',
|
|
59
|
+
docs: {
|
|
60
|
+
description: 'Forbid a package from importing itself by its own package name.',
|
|
61
|
+
},
|
|
62
|
+
schema: [],
|
|
63
|
+
messages: {
|
|
64
|
+
noPackageSelfImport: 'Do not import \'{{specifier}}\' from inside {{packageName}} itself. Self-name imports resolve through the package "exports" (the built dist for some packages), which duplicates modules and breaks tsc project references. Use a relative or \'#\' subpath import instead.',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
create(context) {
|
|
68
|
+
const filename = path.resolve(context.cwd, context.filename);
|
|
69
|
+
const ownPackageName = findOwnPackageName(path.dirname(filename));
|
|
70
|
+
|
|
71
|
+
if (ownPackageName === null) {
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function checkSource(source) {
|
|
76
|
+
if (!source || source.type !== 'Literal' || typeof source.value !== 'string') {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (getImportedPackageName(source.value) === ownPackageName) {
|
|
81
|
+
context.report({
|
|
82
|
+
node: source,
|
|
83
|
+
messageId: 'noPackageSelfImport',
|
|
84
|
+
data: { specifier: source.value, packageName: ownPackageName },
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
ImportDeclaration(node) {
|
|
91
|
+
checkSource(node.source);
|
|
92
|
+
},
|
|
93
|
+
ExportNamedDeclaration(node) {
|
|
94
|
+
checkSource(node.source);
|
|
95
|
+
},
|
|
96
|
+
ExportAllDeclaration(node) {
|
|
97
|
+
checkSource(node.source);
|
|
98
|
+
},
|
|
99
|
+
ImportExpression(node) {
|
|
100
|
+
checkSource(node.source);
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
},
|
|
104
|
+
};
|