@rsdoctor/core 1.5.11 → 1.5.12
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.
|
@@ -52,28 +52,103 @@ function normalizePathForCompare(filePath) {
|
|
|
52
52
|
const cleanPath = splitIndex === 1 / 0 ? filePath : filePath.slice(0, splitIndex);
|
|
53
53
|
return external_path_default().normalize(cleanPath);
|
|
54
54
|
}
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
55
|
+
function isDefinitelyEsmFile(filePath) {
|
|
56
|
+
return '.mjs' === external_path_default().extname(normalizePathForCompare(filePath));
|
|
57
|
+
}
|
|
58
|
+
function isDeclaredEsmEntry(filePath, esmEntries, toRealPath) {
|
|
59
|
+
const realPath = toRealPath(filePath);
|
|
60
|
+
return esmEntries.some((esmEntry)=>realPath === toRealPath(esmEntry));
|
|
61
|
+
}
|
|
62
|
+
function isRecord(value) {
|
|
63
|
+
return null !== value && 'object' == typeof value && !Array.isArray(value);
|
|
64
|
+
}
|
|
65
|
+
function substituteExportPattern(target, wildcard) {
|
|
66
|
+
return target.replace(/\*/g, wildcard);
|
|
67
|
+
}
|
|
68
|
+
function toPackagePath(pkgRoot, target, wildcard) {
|
|
69
|
+
return external_path_default().resolve(pkgRoot, substituteExportPattern(target, wildcard));
|
|
70
|
+
}
|
|
71
|
+
function collectStringTargets(value, wildcard) {
|
|
72
|
+
if ('string' == typeof value) return [
|
|
73
|
+
substituteExportPattern(value, wildcard)
|
|
74
|
+
];
|
|
75
|
+
if (Array.isArray(value)) return value.flatMap((item)=>collectStringTargets(item, wildcard));
|
|
76
|
+
if (!isRecord(value)) return [];
|
|
77
|
+
return Object.values(value).flatMap((child)=>collectStringTargets(child, wildcard));
|
|
78
|
+
}
|
|
79
|
+
function collectEsmTargets(exportEntry, pkgRoot, wildcard) {
|
|
80
|
+
const entries = new Set();
|
|
81
|
+
const addTargets = (value)=>{
|
|
82
|
+
for (const target of collectStringTargets(value, wildcard))entries.add(toPackagePath(pkgRoot, target, ''));
|
|
83
|
+
};
|
|
84
|
+
const visit = (value)=>{
|
|
85
|
+
if ('string' == typeof value || Array.isArray(value)) return void addTargets(value);
|
|
86
|
+
if (!isRecord(value)) return;
|
|
87
|
+
addTargets(value['import']);
|
|
88
|
+
addTargets(value['module']);
|
|
89
|
+
for (const child of Object.values(value))if (isRecord(child) || Array.isArray(child)) visit(child);
|
|
90
|
+
};
|
|
91
|
+
visit(exportEntry);
|
|
92
|
+
return entries;
|
|
93
|
+
}
|
|
94
|
+
function hasSubpathExportKeys(exports1) {
|
|
95
|
+
return Object.keys(exports1).some((key)=>'.' === key || key.startsWith('./'));
|
|
96
|
+
}
|
|
97
|
+
function matchPatternExportKey(patternKey, exportKey) {
|
|
98
|
+
const wildcardIndex = patternKey.indexOf('*');
|
|
99
|
+
if (wildcardIndex < 0) return null;
|
|
100
|
+
const prefix = patternKey.slice(0, wildcardIndex);
|
|
101
|
+
const suffix = patternKey.slice(wildcardIndex + 1);
|
|
102
|
+
if (!exportKey.startsWith(prefix) || !exportKey.endsWith(suffix)) return null;
|
|
103
|
+
return exportKey.slice(prefix.length, exportKey.length - suffix.length);
|
|
104
|
+
}
|
|
105
|
+
function isPatternExportKey(key) {
|
|
106
|
+
return key.indexOf('*') === key.lastIndexOf('*') && key.includes('*');
|
|
107
|
+
}
|
|
108
|
+
function patternKeyCompare(keyA, keyB) {
|
|
109
|
+
const baseLengthA = keyA.includes('*') ? keyA.indexOf('*') + 1 : keyA.length;
|
|
110
|
+
const baseLengthB = keyB.includes('*') ? keyB.indexOf('*') + 1 : keyB.length;
|
|
111
|
+
if (baseLengthA > baseLengthB) return -1;
|
|
112
|
+
if (baseLengthB > baseLengthA) return 1;
|
|
113
|
+
if (!keyA.includes('*')) return 1;
|
|
114
|
+
if (!keyB.includes('*')) return -1;
|
|
115
|
+
if (keyA.length > keyB.length) return -1;
|
|
116
|
+
if (keyB.length > keyA.length) return 1;
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
119
|
+
function resolveExportEntry(exports1, exportKey) {
|
|
120
|
+
if (Object.prototype.hasOwnProperty.call(exports1, exportKey)) return {
|
|
121
|
+
value: exports1[exportKey],
|
|
122
|
+
wildcard: ''
|
|
123
|
+
};
|
|
124
|
+
const patternEntries = Object.entries(exports1).filter(([key])=>isPatternExportKey(key)).sort(([keyA], [keyB])=>patternKeyCompare(keyA, keyB));
|
|
125
|
+
for (const [key, value] of patternEntries){
|
|
126
|
+
const wildcard = matchPatternExportKey(key, exportKey);
|
|
127
|
+
if (null !== wildcard) return {
|
|
128
|
+
value,
|
|
129
|
+
wildcard
|
|
130
|
+
};
|
|
75
131
|
}
|
|
76
|
-
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
function resolveExportEntryForKey(exportsField, exportKey) {
|
|
135
|
+
if (!isRecord(exportsField)) return null;
|
|
136
|
+
if (!hasSubpathExportKeys(exportsField)) return '.' === exportKey ? {
|
|
137
|
+
value: exportsField,
|
|
138
|
+
wildcard: ''
|
|
139
|
+
} : null;
|
|
140
|
+
return resolveExportEntry(exportsField, exportKey);
|
|
141
|
+
}
|
|
142
|
+
function extractEsmEntries(pkgJson, pkgRoot, exportKey) {
|
|
143
|
+
const { exports: exportsField, module: moduleField } = pkgJson;
|
|
144
|
+
const resolvedExport = resolveExportEntryForKey(exportsField, exportKey);
|
|
145
|
+
const entries = resolvedExport ? collectEsmTargets(resolvedExport.value, pkgRoot, resolvedExport.wildcard) : new Set();
|
|
146
|
+
if ('.' === exportKey && 'string' == typeof moduleField) entries.add(external_path_default().resolve(pkgRoot, moduleField));
|
|
147
|
+
return entries;
|
|
148
|
+
}
|
|
149
|
+
function getExportKeyFromRequest(packageName, request) {
|
|
150
|
+
if (request === packageName) return '.';
|
|
151
|
+
if (request.startsWith(`${packageName}/`)) return `.${request.slice(packageName.length)}`;
|
|
77
152
|
return null;
|
|
78
153
|
}
|
|
79
154
|
const rule = (0, external_rule_cjs_namespaceObject.defineRule)(()=>({
|
|
@@ -121,10 +196,15 @@ const rule = (0, external_rule_cjs_namespaceObject.defineRule)(()=>({
|
|
|
121
196
|
const pkg = packageGraph.getPackageByModule(dep.dependency);
|
|
122
197
|
if (!pkg?.root) continue;
|
|
123
198
|
const pkgJson = readPkgJson(pkg.root);
|
|
124
|
-
|
|
125
|
-
|
|
199
|
+
if (ruleConfig.ignore.some((p)=>pkg.name.includes(p)) || !pkgJson) continue;
|
|
200
|
+
const exportKey = getExportKeyFromRequest(pkg.name, dep.request);
|
|
201
|
+
if (!exportKey) continue;
|
|
202
|
+
const esmEntries = extractEsmEntries(pkgJson, pkg.root, exportKey);
|
|
203
|
+
if (0 === esmEntries.size) continue;
|
|
204
|
+
const esmEntryList = Array.from(esmEntries);
|
|
126
205
|
const resolvedModuleRealPath = toRealPath(dep.dependency.path);
|
|
127
|
-
if (resolvedModuleRealPath
|
|
206
|
+
if (isDefinitelyEsmFile(resolvedModuleRealPath)) continue;
|
|
207
|
+
if (isDeclaredEsmEntry(resolvedModuleRealPath, esmEntryList, toRealPath)) continue;
|
|
128
208
|
const groupKey = `${pkg.name}::${resolvedModuleRealPath}`;
|
|
129
209
|
const issuer = {
|
|
130
210
|
id: dep.module.id,
|
|
@@ -135,7 +215,7 @@ const rule = (0, external_rule_cjs_namespaceObject.defineRule)(()=>({
|
|
|
135
215
|
else groups.set(groupKey, {
|
|
136
216
|
packageName: pkg.name,
|
|
137
217
|
packageVersion: pkg.version,
|
|
138
|
-
esmEntry,
|
|
218
|
+
esmEntry: esmEntryList[0],
|
|
139
219
|
resolvedModule: {
|
|
140
220
|
id: dep.dependency.id,
|
|
141
221
|
path: dep.dependency.path,
|
|
@@ -14,28 +14,103 @@ function normalizePathForCompare(filePath) {
|
|
|
14
14
|
const cleanPath = splitIndex === 1 / 0 ? filePath : filePath.slice(0, splitIndex);
|
|
15
15
|
return path.normalize(cleanPath);
|
|
16
16
|
}
|
|
17
|
-
function
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
17
|
+
function isDefinitelyEsmFile(filePath) {
|
|
18
|
+
return '.mjs' === path.extname(normalizePathForCompare(filePath));
|
|
19
|
+
}
|
|
20
|
+
function isDeclaredEsmEntry(filePath, esmEntries, toRealPath) {
|
|
21
|
+
const realPath = toRealPath(filePath);
|
|
22
|
+
return esmEntries.some((esmEntry)=>realPath === toRealPath(esmEntry));
|
|
23
|
+
}
|
|
24
|
+
function isRecord(value) {
|
|
25
|
+
return null !== value && 'object' == typeof value && !Array.isArray(value);
|
|
26
|
+
}
|
|
27
|
+
function substituteExportPattern(target, wildcard) {
|
|
28
|
+
return target.replace(/\*/g, wildcard);
|
|
29
|
+
}
|
|
30
|
+
function toPackagePath(pkgRoot, target, wildcard) {
|
|
31
|
+
return path.resolve(pkgRoot, substituteExportPattern(target, wildcard));
|
|
32
|
+
}
|
|
33
|
+
function collectStringTargets(value, wildcard) {
|
|
34
|
+
if ('string' == typeof value) return [
|
|
35
|
+
substituteExportPattern(value, wildcard)
|
|
36
|
+
];
|
|
37
|
+
if (Array.isArray(value)) return value.flatMap((item)=>collectStringTargets(item, wildcard));
|
|
38
|
+
if (!isRecord(value)) return [];
|
|
39
|
+
return Object.values(value).flatMap((child)=>collectStringTargets(child, wildcard));
|
|
40
|
+
}
|
|
41
|
+
function collectEsmTargets(exportEntry, pkgRoot, wildcard) {
|
|
42
|
+
const entries = new Set();
|
|
43
|
+
const addTargets = (value)=>{
|
|
44
|
+
for (const target of collectStringTargets(value, wildcard))entries.add(toPackagePath(pkgRoot, target, ''));
|
|
45
|
+
};
|
|
46
|
+
const visit = (value)=>{
|
|
47
|
+
if ('string' == typeof value || Array.isArray(value)) return void addTargets(value);
|
|
48
|
+
if (!isRecord(value)) return;
|
|
49
|
+
addTargets(value['import']);
|
|
50
|
+
addTargets(value['module']);
|
|
51
|
+
for (const child of Object.values(value))if (isRecord(child) || Array.isArray(child)) visit(child);
|
|
52
|
+
};
|
|
53
|
+
visit(exportEntry);
|
|
54
|
+
return entries;
|
|
55
|
+
}
|
|
56
|
+
function hasSubpathExportKeys(exports) {
|
|
57
|
+
return Object.keys(exports).some((key)=>'.' === key || key.startsWith('./'));
|
|
58
|
+
}
|
|
59
|
+
function matchPatternExportKey(patternKey, exportKey) {
|
|
60
|
+
const wildcardIndex = patternKey.indexOf('*');
|
|
61
|
+
if (wildcardIndex < 0) return null;
|
|
62
|
+
const prefix = patternKey.slice(0, wildcardIndex);
|
|
63
|
+
const suffix = patternKey.slice(wildcardIndex + 1);
|
|
64
|
+
if (!exportKey.startsWith(prefix) || !exportKey.endsWith(suffix)) return null;
|
|
65
|
+
return exportKey.slice(prefix.length, exportKey.length - suffix.length);
|
|
66
|
+
}
|
|
67
|
+
function isPatternExportKey(key) {
|
|
68
|
+
return key.indexOf('*') === key.lastIndexOf('*') && key.includes('*');
|
|
69
|
+
}
|
|
70
|
+
function patternKeyCompare(keyA, keyB) {
|
|
71
|
+
const baseLengthA = keyA.includes('*') ? keyA.indexOf('*') + 1 : keyA.length;
|
|
72
|
+
const baseLengthB = keyB.includes('*') ? keyB.indexOf('*') + 1 : keyB.length;
|
|
73
|
+
if (baseLengthA > baseLengthB) return -1;
|
|
74
|
+
if (baseLengthB > baseLengthA) return 1;
|
|
75
|
+
if (!keyA.includes('*')) return 1;
|
|
76
|
+
if (!keyB.includes('*')) return -1;
|
|
77
|
+
if (keyA.length > keyB.length) return -1;
|
|
78
|
+
if (keyB.length > keyA.length) return 1;
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
function resolveExportEntry(exports, exportKey) {
|
|
82
|
+
if (Object.prototype.hasOwnProperty.call(exports, exportKey)) return {
|
|
83
|
+
value: exports[exportKey],
|
|
84
|
+
wildcard: ''
|
|
85
|
+
};
|
|
86
|
+
const patternEntries = Object.entries(exports).filter(([key])=>isPatternExportKey(key)).sort(([keyA], [keyB])=>patternKeyCompare(keyA, keyB));
|
|
87
|
+
for (const [key, value] of patternEntries){
|
|
88
|
+
const wildcard = matchPatternExportKey(key, exportKey);
|
|
89
|
+
if (null !== wildcard) return {
|
|
90
|
+
value,
|
|
91
|
+
wildcard
|
|
92
|
+
};
|
|
37
93
|
}
|
|
38
|
-
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
function resolveExportEntryForKey(exportsField, exportKey) {
|
|
97
|
+
if (!isRecord(exportsField)) return null;
|
|
98
|
+
if (!hasSubpathExportKeys(exportsField)) return '.' === exportKey ? {
|
|
99
|
+
value: exportsField,
|
|
100
|
+
wildcard: ''
|
|
101
|
+
} : null;
|
|
102
|
+
return resolveExportEntry(exportsField, exportKey);
|
|
103
|
+
}
|
|
104
|
+
function extractEsmEntries(pkgJson, pkgRoot, exportKey) {
|
|
105
|
+
const { exports: exportsField, module: moduleField } = pkgJson;
|
|
106
|
+
const resolvedExport = resolveExportEntryForKey(exportsField, exportKey);
|
|
107
|
+
const entries = resolvedExport ? collectEsmTargets(resolvedExport.value, pkgRoot, resolvedExport.wildcard) : new Set();
|
|
108
|
+
if ('.' === exportKey && 'string' == typeof moduleField) entries.add(path.resolve(pkgRoot, moduleField));
|
|
109
|
+
return entries;
|
|
110
|
+
}
|
|
111
|
+
function getExportKeyFromRequest(packageName, request) {
|
|
112
|
+
if (request === packageName) return '.';
|
|
113
|
+
if (request.startsWith(`${packageName}/`)) return `.${request.slice(packageName.length)}`;
|
|
39
114
|
return null;
|
|
40
115
|
}
|
|
41
116
|
const rule = defineRule(()=>({
|
|
@@ -83,10 +158,15 @@ const rule = defineRule(()=>({
|
|
|
83
158
|
const pkg = packageGraph.getPackageByModule(dep.dependency);
|
|
84
159
|
if (!pkg?.root) continue;
|
|
85
160
|
const pkgJson = readPkgJson(pkg.root);
|
|
86
|
-
|
|
87
|
-
|
|
161
|
+
if (ruleConfig.ignore.some((p)=>pkg.name.includes(p)) || !pkgJson) continue;
|
|
162
|
+
const exportKey = getExportKeyFromRequest(pkg.name, dep.request);
|
|
163
|
+
if (!exportKey) continue;
|
|
164
|
+
const esmEntries = extractEsmEntries(pkgJson, pkg.root, exportKey);
|
|
165
|
+
if (0 === esmEntries.size) continue;
|
|
166
|
+
const esmEntryList = Array.from(esmEntries);
|
|
88
167
|
const resolvedModuleRealPath = toRealPath(dep.dependency.path);
|
|
89
|
-
if (resolvedModuleRealPath
|
|
168
|
+
if (isDefinitelyEsmFile(resolvedModuleRealPath)) continue;
|
|
169
|
+
if (isDeclaredEsmEntry(resolvedModuleRealPath, esmEntryList, toRealPath)) continue;
|
|
90
170
|
const groupKey = `${pkg.name}::${resolvedModuleRealPath}`;
|
|
91
171
|
const issuer = {
|
|
92
172
|
id: dep.module.id,
|
|
@@ -97,7 +177,7 @@ const rule = defineRule(()=>({
|
|
|
97
177
|
else groups.set(groupKey, {
|
|
98
178
|
packageName: pkg.name,
|
|
99
179
|
packageVersion: pkg.version,
|
|
100
|
-
esmEntry,
|
|
180
|
+
esmEntry: esmEntryList[0],
|
|
101
181
|
resolvedModule: {
|
|
102
182
|
id: dep.dependency.id,
|
|
103
183
|
path: dep.dependency.path,
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Linter } from '@rsdoctor/types';
|
|
2
|
+
export declare const rules: Linter.RuleData[];
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Linter } from '@rsdoctor/types';
|
|
2
|
+
export declare const rules: Linter.RuleData[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rsdoctor/core",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.12",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/web-infra-dev/rsdoctor",
|
|
@@ -90,19 +90,19 @@
|
|
|
90
90
|
"@rsbuild/plugin-check-syntax": "1.6.1",
|
|
91
91
|
"@rspack/resolver": "0.2.8",
|
|
92
92
|
"es-toolkit": "^1.45.1",
|
|
93
|
-
"filesize": "^
|
|
93
|
+
"filesize": "^11.0.17",
|
|
94
94
|
"fs-extra": "^11.1.1",
|
|
95
95
|
"semver": "^7.7.4",
|
|
96
96
|
"source-map": "^0.7.6",
|
|
97
|
-
"@rsdoctor/
|
|
98
|
-
"@rsdoctor/
|
|
99
|
-
"@rsdoctor/
|
|
100
|
-
"@rsdoctor/
|
|
97
|
+
"@rsdoctor/graph": "1.5.12",
|
|
98
|
+
"@rsdoctor/types": "1.5.12",
|
|
99
|
+
"@rsdoctor/sdk": "1.5.12",
|
|
100
|
+
"@rsdoctor/utils": "1.5.12"
|
|
101
101
|
},
|
|
102
102
|
"devDependencies": {
|
|
103
|
-
"@rspack/core": "2.0.
|
|
103
|
+
"@rspack/core": "2.0.3",
|
|
104
104
|
"@types/fs-extra": "^11.0.4",
|
|
105
|
-
"@types/node": "^
|
|
105
|
+
"@types/node": "^24.12.3",
|
|
106
106
|
"@types/node-fetch": "^2.6.13",
|
|
107
107
|
"@types/semver": "^7.7.1",
|
|
108
108
|
"@types/tapable": "2.3.0",
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"string-loader": "0.0.1",
|
|
112
112
|
"ts-loader": "^9.5.7",
|
|
113
113
|
"tslib": "2.8.1",
|
|
114
|
-
"typescript": "^
|
|
114
|
+
"typescript": "^6.0.3",
|
|
115
115
|
"webpack": "^5.105.4",
|
|
116
116
|
"@scripts/test-helper": "0.1.1"
|
|
117
117
|
},
|