@node-cli/bundlecheck 1.4.1 → 1.5.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/README.md +58 -7
- package/dist/bundlecheck.js +10 -1
- package/dist/bundlecheck.js.map +1 -1
- package/dist/bundler.d.ts +19 -2
- package/dist/bundler.js +179 -30
- package/dist/bundler.js.map +1 -1
- package/dist/cache.js +29 -6
- package/dist/cache.js.map +1 -1
- package/dist/defaults.d.ts +10 -0
- package/dist/defaults.js +18 -1
- package/dist/defaults.js.map +1 -1
- package/dist/exports-installer.d.ts +19 -0
- package/dist/exports-installer.js +115 -0
- package/dist/exports-installer.js.map +1 -0
- package/dist/exports.d.ts +43 -0
- package/dist/exports.js +330 -0
- package/dist/exports.js.map +1 -0
- package/dist/index.d.ts +81 -2
- package/dist/index.js +64 -7
- package/dist/index.js.map +1 -1
- package/dist/parse.js +2 -2
- package/dist/parse.js.map +1 -1
- package/package.json +2 -2
package/dist/exports.js
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Resolve a relative import path to an absolute file path.
|
|
5
|
+
*/ function resolveImportPath(basePath, importPath) {
|
|
6
|
+
// Remove quotes and trim.
|
|
7
|
+
let cleanPath = importPath.replace(/['"]/g, "").trim();
|
|
8
|
+
// Only handle relative imports.
|
|
9
|
+
if (!cleanPath.startsWith(".")) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Strip .js/.mjs extension if present (TypeScript uses .js in imports but
|
|
14
|
+
* .d.ts for types).
|
|
15
|
+
*/ cleanPath = cleanPath.replace(/\.(m?js)$/, "");
|
|
16
|
+
const baseDir = path.dirname(basePath);
|
|
17
|
+
const resolved = path.resolve(baseDir, cleanPath);
|
|
18
|
+
// Try different extensions for the resolved path.
|
|
19
|
+
const extensions = [
|
|
20
|
+
".d.ts",
|
|
21
|
+
".d.mts",
|
|
22
|
+
".ts",
|
|
23
|
+
""
|
|
24
|
+
];
|
|
25
|
+
for (const ext of extensions){
|
|
26
|
+
const tryPath = resolved + ext;
|
|
27
|
+
if (fs.existsSync(tryPath) && fs.statSync(tryPath).isFile()) {
|
|
28
|
+
return tryPath;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Try index files in directory.
|
|
32
|
+
for (const ext of [
|
|
33
|
+
".d.ts",
|
|
34
|
+
".d.mts",
|
|
35
|
+
".ts"
|
|
36
|
+
]){
|
|
37
|
+
const indexPath = path.join(resolved, `index${ext}`);
|
|
38
|
+
if (fs.existsSync(indexPath) && fs.statSync(indexPath).isFile()) {
|
|
39
|
+
return indexPath;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Parse a TypeScript declaration file (.d.ts) to extract named exports.
|
|
46
|
+
* Recursively follows re-exports up to a maximum depth.
|
|
47
|
+
*/ function parseDeclarationFile(filePath, content, visited = new Set(), depth = 0) {
|
|
48
|
+
const MAX_DEPTH = 10;
|
|
49
|
+
const MAX_FILES = 500;
|
|
50
|
+
if (depth > MAX_DEPTH || visited.size > MAX_FILES) {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
// Avoid circular imports.
|
|
54
|
+
const normalizedPath = path.resolve(filePath);
|
|
55
|
+
if (visited.has(normalizedPath)) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
visited.add(normalizedPath);
|
|
59
|
+
const exports = [];
|
|
60
|
+
const seenNames = new Set();
|
|
61
|
+
const addExport = (name, kind)=>{
|
|
62
|
+
// Skip internal/private exports and TypeScript utility types.
|
|
63
|
+
if (name.startsWith("_") || name === "default" || seenNames.has(name)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
seenNames.add(name);
|
|
67
|
+
exports.push({
|
|
68
|
+
name,
|
|
69
|
+
kind
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
// Pattern for: export * from './path'.
|
|
73
|
+
const reExportAllPattern = /export\s+\*\s+from\s+['"]([^'"]+)['"]/g;
|
|
74
|
+
// Pattern for: export type { Name, Name2 } from './path' (type-only exports).
|
|
75
|
+
const reExportTypePattern = /export\s+type\s+\{([^}]+)\}\s+from\s+['"]([^'"]+)['"]/g;
|
|
76
|
+
/**
|
|
77
|
+
* Pattern for: export { Name, Name2 } from './path' (value exports - NOT
|
|
78
|
+
* type).
|
|
79
|
+
*/ const reExportValuePattern = /export\s+\{([^}]+)\}\s+from\s+['"]([^'"]+)['"]/g;
|
|
80
|
+
// Pattern for: export declare function Name.
|
|
81
|
+
const functionPattern = /export\s+declare\s+function\s+(\w+)/g;
|
|
82
|
+
// Pattern for: export declare class Name.
|
|
83
|
+
const classPattern = /export\s+declare\s+class\s+(\w+)/g;
|
|
84
|
+
// Pattern for: export declare const Name.
|
|
85
|
+
const constPattern = /export\s+declare\s+const\s+(\w+)/g;
|
|
86
|
+
// Pattern for: export declare type Name.
|
|
87
|
+
const typePattern = /export\s+declare\s+type\s+(\w+)/g;
|
|
88
|
+
// Pattern for: export type Name = ... (without declare).
|
|
89
|
+
const typePattern2 = /export\s+type\s+(\w+)\s*[=<]/g;
|
|
90
|
+
// Pattern for: export type { Name } (local re-export without from).
|
|
91
|
+
const typeExportPattern = /export\s+type\s+\{([^}]+)\}\s*;/g;
|
|
92
|
+
// Pattern for: export interface Name.
|
|
93
|
+
const interfacePattern = /export\s+(?:declare\s+)?interface\s+(\w+)/g;
|
|
94
|
+
// Pattern for: export declare enum Name.
|
|
95
|
+
const enumPattern = /export\s+declare\s+enum\s+(\w+)/g;
|
|
96
|
+
// Pattern for: export { Name, Name2 } (without from - local exports).
|
|
97
|
+
const namedExportPattern = /export\s+\{([^}]+)\}\s*;/g;
|
|
98
|
+
// Pattern for: export declare const Name: ... (component style).
|
|
99
|
+
const componentPattern = /export\s+declare\s+const\s+(\w+)\s*:/g;
|
|
100
|
+
// Pattern for: export function Name (without declare).
|
|
101
|
+
const functionPattern2 = /export\s+function\s+(\w+)/g;
|
|
102
|
+
// Pattern for: export class Name (without declare).
|
|
103
|
+
const classPattern2 = /export\s+class\s+(\w+)/g;
|
|
104
|
+
// Pattern for: export const Name (without declare).
|
|
105
|
+
const constPattern2 = /export\s+const\s+(\w+)/g;
|
|
106
|
+
// Helper to extract all matches from a regex.
|
|
107
|
+
const extractMatches = (pattern, text)=>{
|
|
108
|
+
const matches = [];
|
|
109
|
+
let result = pattern.exec(text);
|
|
110
|
+
while(result !== null){
|
|
111
|
+
matches.push(result);
|
|
112
|
+
result = pattern.exec(text);
|
|
113
|
+
}
|
|
114
|
+
return matches;
|
|
115
|
+
};
|
|
116
|
+
// Handle: export * from './path' - recursively parse.
|
|
117
|
+
for (const match of extractMatches(reExportAllPattern, content)){
|
|
118
|
+
const importPath = match[1];
|
|
119
|
+
const resolvedPath = resolveImportPath(filePath, importPath);
|
|
120
|
+
if (resolvedPath) {
|
|
121
|
+
try {
|
|
122
|
+
const importedContent = fs.readFileSync(resolvedPath, "utf-8");
|
|
123
|
+
const importedExports = parseDeclarationFile(resolvedPath, importedContent, visited, depth + 1);
|
|
124
|
+
for (const exp of importedExports){
|
|
125
|
+
addExport(exp.name, exp.kind);
|
|
126
|
+
}
|
|
127
|
+
} catch {
|
|
128
|
+
// Ignore read errors.
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Handle: export type { Name } from './path' (type-only exports).
|
|
133
|
+
for (const match of extractMatches(reExportTypePattern, content)){
|
|
134
|
+
const exportList = match[1];
|
|
135
|
+
const names = exportList.split(",").map((s)=>{
|
|
136
|
+
const trimmed = s.trim();
|
|
137
|
+
// Handle "Name as Alias".
|
|
138
|
+
const asMatch = trimmed.match(/(\w+)\s+as\s+(\w+)/);
|
|
139
|
+
if (asMatch) {
|
|
140
|
+
return asMatch[2];
|
|
141
|
+
}
|
|
142
|
+
return trimmed;
|
|
143
|
+
});
|
|
144
|
+
for (const name of names){
|
|
145
|
+
if (name && /^\w+$/.test(name)) {
|
|
146
|
+
addExport(name, "type");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Handle: export { Name } from './path' (value exports).
|
|
151
|
+
for (const match of extractMatches(reExportValuePattern, content)){
|
|
152
|
+
// Skip if this is actually a type export (already handled above).
|
|
153
|
+
const fullMatch = match[0];
|
|
154
|
+
if (fullMatch.includes("export type")) {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
const exportList = match[1];
|
|
158
|
+
const names = exportList.split(",").map((s)=>{
|
|
159
|
+
const trimmed = s.trim();
|
|
160
|
+
// Handle "Name as Alias".
|
|
161
|
+
const asMatch = trimmed.match(/(\w+)\s+as\s+(\w+)/);
|
|
162
|
+
if (asMatch) {
|
|
163
|
+
return asMatch[2];
|
|
164
|
+
}
|
|
165
|
+
// Handle "type Name" syntax within the braces.
|
|
166
|
+
const typeMatch = trimmed.match(/type\s+(\w+)/);
|
|
167
|
+
if (typeMatch) {
|
|
168
|
+
/**
|
|
169
|
+
* This is a type being re-exported, skip it (will be handled by type
|
|
170
|
+
* pattern).
|
|
171
|
+
*/ return null;
|
|
172
|
+
}
|
|
173
|
+
return trimmed;
|
|
174
|
+
});
|
|
175
|
+
for (const name of names){
|
|
176
|
+
if (name && /^\w+$/.test(name)) {
|
|
177
|
+
addExport(name, "unknown");
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Extract functions.
|
|
182
|
+
for (const match of extractMatches(functionPattern, content)){
|
|
183
|
+
addExport(match[1], "function");
|
|
184
|
+
}
|
|
185
|
+
for (const match of extractMatches(functionPattern2, content)){
|
|
186
|
+
addExport(match[1], "function");
|
|
187
|
+
}
|
|
188
|
+
// Extract classes.
|
|
189
|
+
for (const match of extractMatches(classPattern, content)){
|
|
190
|
+
addExport(match[1], "class");
|
|
191
|
+
}
|
|
192
|
+
for (const match of extractMatches(classPattern2, content)){
|
|
193
|
+
addExport(match[1], "class");
|
|
194
|
+
}
|
|
195
|
+
// Extract const (includes React components).
|
|
196
|
+
for (const match of extractMatches(constPattern, content)){
|
|
197
|
+
addExport(match[1], "const");
|
|
198
|
+
}
|
|
199
|
+
for (const match of extractMatches(constPattern2, content)){
|
|
200
|
+
addExport(match[1], "const");
|
|
201
|
+
}
|
|
202
|
+
// Also catch component-style declarations.
|
|
203
|
+
for (const match of extractMatches(componentPattern, content)){
|
|
204
|
+
addExport(match[1], "const");
|
|
205
|
+
}
|
|
206
|
+
// Extract types (declare type).
|
|
207
|
+
for (const match of extractMatches(typePattern, content)){
|
|
208
|
+
addExport(match[1], "type");
|
|
209
|
+
}
|
|
210
|
+
// Extract types (export type X =).
|
|
211
|
+
for (const match of extractMatches(typePattern2, content)){
|
|
212
|
+
addExport(match[1], "type");
|
|
213
|
+
}
|
|
214
|
+
// Extract type exports (export type { X }).
|
|
215
|
+
for (const match of extractMatches(typeExportPattern, content)){
|
|
216
|
+
const exportList = match[1];
|
|
217
|
+
const names = exportList.split(",").map((s)=>s.trim());
|
|
218
|
+
for (const name of names){
|
|
219
|
+
if (name && /^\w+$/.test(name)) {
|
|
220
|
+
addExport(name, "type");
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// Extract interfaces.
|
|
225
|
+
for (const match of extractMatches(interfacePattern, content)){
|
|
226
|
+
addExport(match[1], "interface");
|
|
227
|
+
}
|
|
228
|
+
// Extract enums.
|
|
229
|
+
for (const match of extractMatches(enumPattern, content)){
|
|
230
|
+
addExport(match[1], "enum");
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Extract named exports from export { ... } (without from - these are local
|
|
234
|
+
* exports).
|
|
235
|
+
*/ for (const match of extractMatches(namedExportPattern, content)){
|
|
236
|
+
const exportList = match[1];
|
|
237
|
+
// Skip if this looks like a type export (already handled above).
|
|
238
|
+
if (content.substring(match.index - 5, match.index).includes("type")) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const names = exportList.split(",").map((s)=>{
|
|
242
|
+
const trimmed = s.trim();
|
|
243
|
+
const asMatch = trimmed.match(/(\w+)\s+as\s+(\w+)/);
|
|
244
|
+
if (asMatch) {
|
|
245
|
+
return asMatch[2];
|
|
246
|
+
}
|
|
247
|
+
const typeMatch = trimmed.match(/type\s+(\w+)/);
|
|
248
|
+
if (typeMatch) {
|
|
249
|
+
return typeMatch[1];
|
|
250
|
+
}
|
|
251
|
+
return trimmed;
|
|
252
|
+
});
|
|
253
|
+
for (const name of names){
|
|
254
|
+
if (name && /^\w+$/.test(name)) {
|
|
255
|
+
addExport(name, "unknown");
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return exports;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Get named exports from an installed package by parsing its type definitions.
|
|
263
|
+
*
|
|
264
|
+
* @param tmpDir - The temporary directory where the package is installed
|
|
265
|
+
* @param packageName - The package name (e.g., "@mantine/core")
|
|
266
|
+
* @returns ParsedExports containing the list of exports and count
|
|
267
|
+
*
|
|
268
|
+
*/ export function getNamedExports(tmpDir, packageName) {
|
|
269
|
+
const packageDir = path.join(tmpDir, "node_modules", packageName);
|
|
270
|
+
const emptyResult = {
|
|
271
|
+
exports: [],
|
|
272
|
+
count: 0,
|
|
273
|
+
runtimeExports: [],
|
|
274
|
+
runtimeCount: 0
|
|
275
|
+
};
|
|
276
|
+
// Try to read package.json to find the types entry.
|
|
277
|
+
const pkgJsonPath = path.join(packageDir, "package.json");
|
|
278
|
+
if (!fs.existsSync(pkgJsonPath)) {
|
|
279
|
+
return emptyResult;
|
|
280
|
+
}
|
|
281
|
+
let typesEntry;
|
|
282
|
+
try {
|
|
283
|
+
const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
|
|
284
|
+
// Look for types in order of preference.
|
|
285
|
+
typesEntry = pkgJson.types || pkgJson.typings || pkgJson.exports?.["."]?.types || typeof pkgJson.exports?.["."] === "object" && pkgJson.exports["."].types;
|
|
286
|
+
// If no types field, try common patterns.
|
|
287
|
+
if (!typesEntry) {
|
|
288
|
+
const commonPaths = [
|
|
289
|
+
"dist/index.d.ts",
|
|
290
|
+
"lib/index.d.ts",
|
|
291
|
+
"index.d.ts",
|
|
292
|
+
"types/index.d.ts"
|
|
293
|
+
];
|
|
294
|
+
for (const tryPath of commonPaths){
|
|
295
|
+
if (fs.existsSync(path.join(packageDir, tryPath))) {
|
|
296
|
+
typesEntry = tryPath;
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
} catch {
|
|
302
|
+
return emptyResult;
|
|
303
|
+
}
|
|
304
|
+
if (!typesEntry) {
|
|
305
|
+
return emptyResult;
|
|
306
|
+
}
|
|
307
|
+
// Read and parse the types file.
|
|
308
|
+
const typesPath = path.join(packageDir, typesEntry);
|
|
309
|
+
if (!fs.existsSync(typesPath)) {
|
|
310
|
+
return emptyResult;
|
|
311
|
+
}
|
|
312
|
+
try {
|
|
313
|
+
const content = fs.readFileSync(typesPath, "utf-8");
|
|
314
|
+
const exports = parseDeclarationFile(typesPath, content);
|
|
315
|
+
// Sort exports by name for consistent output.
|
|
316
|
+
exports.sort((a, b)=>a.name.localeCompare(b.name));
|
|
317
|
+
// Filter to runtime-only exports (exclude types and interfaces).
|
|
318
|
+
const runtimeExports = exports.filter((e)=>e.kind !== "type" && e.kind !== "interface");
|
|
319
|
+
return {
|
|
320
|
+
exports,
|
|
321
|
+
count: exports.length,
|
|
322
|
+
runtimeExports,
|
|
323
|
+
runtimeCount: runtimeExports.length
|
|
324
|
+
};
|
|
325
|
+
} catch {
|
|
326
|
+
return emptyResult;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
//# sourceMappingURL=exports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/exports.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Represents a named export from a package.\n */\nexport type NamedExport = {\n\t/**\n\t * The export name (e.g., \"Button\", \"useState\").\n\t */\n\tname: string;\n\t/**\n\t * The type of export.\n\t */\n\tkind:\n\t\t| \"function\"\n\t\t| \"class\"\n\t\t| \"const\"\n\t\t| \"type\"\n\t\t| \"interface\"\n\t\t| \"enum\"\n\t\t| \"unknown\";\n};\n\n/**\n * Result from parsing package exports.\n */\nexport type ParsedExports = {\n\t/**\n\t * Array of all named exports found in the package (including types).\n\t */\n\texports: NamedExport[];\n\t/**\n\t * Total count of all named exports (including types).\n\t */\n\tcount: number;\n\t/**\n\t * Array of runtime exports only (excluding types and interfaces).\n\t */\n\truntimeExports: NamedExport[];\n\t/**\n\t * Count of runtime exports only (functions, classes, const, enums).\n\t */\n\truntimeCount: number;\n};\n\n/**\n * Resolve a relative import path to an absolute file path.\n */\nfunction resolveImportPath(\n\tbasePath: string,\n\timportPath: string,\n): string | null {\n\t// Remove quotes and trim.\n\tlet cleanPath = importPath.replace(/['\"]/g, \"\").trim();\n\n\t// Only handle relative imports.\n\tif (!cleanPath.startsWith(\".\")) {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Strip .js/.mjs extension if present (TypeScript uses .js in imports but\n\t * .d.ts for types).\n\t */\n\tcleanPath = cleanPath.replace(/\\.(m?js)$/, \"\");\n\n\tconst baseDir = path.dirname(basePath);\n\tconst resolved = path.resolve(baseDir, cleanPath);\n\n\t// Try different extensions for the resolved path.\n\tconst extensions = [\".d.ts\", \".d.mts\", \".ts\", \"\"];\n\tfor (const ext of extensions) {\n\t\tconst tryPath = resolved + ext;\n\t\tif (fs.existsSync(tryPath) && fs.statSync(tryPath).isFile()) {\n\t\t\treturn tryPath;\n\t\t}\n\t}\n\n\t// Try index files in directory.\n\tfor (const ext of [\".d.ts\", \".d.mts\", \".ts\"]) {\n\t\tconst indexPath = path.join(resolved, `index${ext}`);\n\t\tif (fs.existsSync(indexPath) && fs.statSync(indexPath).isFile()) {\n\t\t\treturn indexPath;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Parse a TypeScript declaration file (.d.ts) to extract named exports.\n * Recursively follows re-exports up to a maximum depth.\n */\nfunction parseDeclarationFile(\n\tfilePath: string,\n\tcontent: string,\n\tvisited: Set<string> = new Set(),\n\tdepth = 0,\n): NamedExport[] {\n\tconst MAX_DEPTH = 10;\n\tconst MAX_FILES = 500;\n\n\tif (depth > MAX_DEPTH || visited.size > MAX_FILES) {\n\t\treturn [];\n\t}\n\n\t// Avoid circular imports.\n\tconst normalizedPath = path.resolve(filePath);\n\tif (visited.has(normalizedPath)) {\n\t\treturn [];\n\t}\n\tvisited.add(normalizedPath);\n\n\tconst exports: NamedExport[] = [];\n\tconst seenNames = new Set<string>();\n\n\tconst addExport = (name: string, kind: NamedExport[\"kind\"]) => {\n\t\t// Skip internal/private exports and TypeScript utility types.\n\t\tif (name.startsWith(\"_\") || name === \"default\" || seenNames.has(name)) {\n\t\t\treturn;\n\t\t}\n\t\tseenNames.add(name);\n\t\texports.push({ name, kind });\n\t};\n\n\t// Pattern for: export * from './path'.\n\tconst reExportAllPattern = /export\\s+\\*\\s+from\\s+['\"]([^'\"]+)['\"]/g;\n\n\t// Pattern for: export type { Name, Name2 } from './path' (type-only exports).\n\tconst reExportTypePattern =\n\t\t/export\\s+type\\s+\\{([^}]+)\\}\\s+from\\s+['\"]([^'\"]+)['\"]/g;\n\n\t/**\n\t * Pattern for: export { Name, Name2 } from './path' (value exports - NOT\n\t * type).\n\t */\n\tconst reExportValuePattern =\n\t\t/export\\s+\\{([^}]+)\\}\\s+from\\s+['\"]([^'\"]+)['\"]/g;\n\n\t// Pattern for: export declare function Name.\n\tconst functionPattern = /export\\s+declare\\s+function\\s+(\\w+)/g;\n\t// Pattern for: export declare class Name.\n\tconst classPattern = /export\\s+declare\\s+class\\s+(\\w+)/g;\n\t// Pattern for: export declare const Name.\n\tconst constPattern = /export\\s+declare\\s+const\\s+(\\w+)/g;\n\t// Pattern for: export declare type Name.\n\tconst typePattern = /export\\s+declare\\s+type\\s+(\\w+)/g;\n\t// Pattern for: export type Name = ... (without declare).\n\tconst typePattern2 = /export\\s+type\\s+(\\w+)\\s*[=<]/g;\n\t// Pattern for: export type { Name } (local re-export without from).\n\tconst typeExportPattern = /export\\s+type\\s+\\{([^}]+)\\}\\s*;/g;\n\t// Pattern for: export interface Name.\n\tconst interfacePattern = /export\\s+(?:declare\\s+)?interface\\s+(\\w+)/g;\n\t// Pattern for: export declare enum Name.\n\tconst enumPattern = /export\\s+declare\\s+enum\\s+(\\w+)/g;\n\t// Pattern for: export { Name, Name2 } (without from - local exports).\n\tconst namedExportPattern = /export\\s+\\{([^}]+)\\}\\s*;/g;\n\t// Pattern for: export declare const Name: ... (component style).\n\tconst componentPattern = /export\\s+declare\\s+const\\s+(\\w+)\\s*:/g;\n\t// Pattern for: export function Name (without declare).\n\tconst functionPattern2 = /export\\s+function\\s+(\\w+)/g;\n\t// Pattern for: export class Name (without declare).\n\tconst classPattern2 = /export\\s+class\\s+(\\w+)/g;\n\t// Pattern for: export const Name (without declare).\n\tconst constPattern2 = /export\\s+const\\s+(\\w+)/g;\n\n\t// Helper to extract all matches from a regex.\n\tconst extractMatches = (pattern: RegExp, text: string): RegExpExecArray[] => {\n\t\tconst matches: RegExpExecArray[] = [];\n\t\tlet result = pattern.exec(text);\n\t\twhile (result !== null) {\n\t\t\tmatches.push(result);\n\t\t\tresult = pattern.exec(text);\n\t\t}\n\t\treturn matches;\n\t};\n\n\t// Handle: export * from './path' - recursively parse.\n\tfor (const match of extractMatches(reExportAllPattern, content)) {\n\t\tconst importPath = match[1];\n\t\tconst resolvedPath = resolveImportPath(filePath, importPath);\n\t\tif (resolvedPath) {\n\t\t\ttry {\n\t\t\t\tconst importedContent = fs.readFileSync(resolvedPath, \"utf-8\");\n\t\t\t\tconst importedExports = parseDeclarationFile(\n\t\t\t\t\tresolvedPath,\n\t\t\t\t\timportedContent,\n\t\t\t\t\tvisited,\n\t\t\t\t\tdepth + 1,\n\t\t\t\t);\n\t\t\t\tfor (const exp of importedExports) {\n\t\t\t\t\taddExport(exp.name, exp.kind);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Ignore read errors.\n\t\t\t}\n\t\t}\n\t}\n\n\t// Handle: export type { Name } from './path' (type-only exports).\n\tfor (const match of extractMatches(reExportTypePattern, content)) {\n\t\tconst exportList = match[1];\n\t\tconst names = exportList.split(\",\").map((s) => {\n\t\t\tconst trimmed = s.trim();\n\t\t\t// Handle \"Name as Alias\".\n\t\t\tconst asMatch = trimmed.match(/(\\w+)\\s+as\\s+(\\w+)/);\n\t\t\tif (asMatch) {\n\t\t\t\treturn asMatch[2];\n\t\t\t}\n\t\t\treturn trimmed;\n\t\t});\n\n\t\tfor (const name of names) {\n\t\t\tif (name && /^\\w+$/.test(name)) {\n\t\t\t\taddExport(name, \"type\");\n\t\t\t}\n\t\t}\n\t}\n\n\t// Handle: export { Name } from './path' (value exports).\n\tfor (const match of extractMatches(reExportValuePattern, content)) {\n\t\t// Skip if this is actually a type export (already handled above).\n\t\tconst fullMatch = match[0];\n\t\tif (fullMatch.includes(\"export type\")) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst exportList = match[1];\n\t\tconst names = exportList.split(\",\").map((s) => {\n\t\t\tconst trimmed = s.trim();\n\t\t\t// Handle \"Name as Alias\".\n\t\t\tconst asMatch = trimmed.match(/(\\w+)\\s+as\\s+(\\w+)/);\n\t\t\tif (asMatch) {\n\t\t\t\treturn asMatch[2];\n\t\t\t}\n\t\t\t// Handle \"type Name\" syntax within the braces.\n\t\t\tconst typeMatch = trimmed.match(/type\\s+(\\w+)/);\n\t\t\tif (typeMatch) {\n\t\t\t\t/**\n\t\t\t\t * This is a type being re-exported, skip it (will be handled by type\n\t\t\t\t * pattern).\n\t\t\t\t */\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn trimmed;\n\t\t});\n\n\t\tfor (const name of names) {\n\t\t\tif (name && /^\\w+$/.test(name)) {\n\t\t\t\taddExport(name, \"unknown\");\n\t\t\t}\n\t\t}\n\t}\n\n\t// Extract functions.\n\tfor (const match of extractMatches(functionPattern, content)) {\n\t\taddExport(match[1], \"function\");\n\t}\n\tfor (const match of extractMatches(functionPattern2, content)) {\n\t\taddExport(match[1], \"function\");\n\t}\n\n\t// Extract classes.\n\tfor (const match of extractMatches(classPattern, content)) {\n\t\taddExport(match[1], \"class\");\n\t}\n\tfor (const match of extractMatches(classPattern2, content)) {\n\t\taddExport(match[1], \"class\");\n\t}\n\n\t// Extract const (includes React components).\n\tfor (const match of extractMatches(constPattern, content)) {\n\t\taddExport(match[1], \"const\");\n\t}\n\tfor (const match of extractMatches(constPattern2, content)) {\n\t\taddExport(match[1], \"const\");\n\t}\n\n\t// Also catch component-style declarations.\n\tfor (const match of extractMatches(componentPattern, content)) {\n\t\taddExport(match[1], \"const\");\n\t}\n\n\t// Extract types (declare type).\n\tfor (const match of extractMatches(typePattern, content)) {\n\t\taddExport(match[1], \"type\");\n\t}\n\n\t// Extract types (export type X =).\n\tfor (const match of extractMatches(typePattern2, content)) {\n\t\taddExport(match[1], \"type\");\n\t}\n\n\t// Extract type exports (export type { X }).\n\tfor (const match of extractMatches(typeExportPattern, content)) {\n\t\tconst exportList = match[1];\n\t\tconst names = exportList.split(\",\").map((s) => s.trim());\n\t\tfor (const name of names) {\n\t\t\tif (name && /^\\w+$/.test(name)) {\n\t\t\t\taddExport(name, \"type\");\n\t\t\t}\n\t\t}\n\t}\n\n\t// Extract interfaces.\n\tfor (const match of extractMatches(interfacePattern, content)) {\n\t\taddExport(match[1], \"interface\");\n\t}\n\n\t// Extract enums.\n\tfor (const match of extractMatches(enumPattern, content)) {\n\t\taddExport(match[1], \"enum\");\n\t}\n\n\t/**\n\t * Extract named exports from export { ... } (without from - these are local\n\t * exports).\n\t */\n\tfor (const match of extractMatches(namedExportPattern, content)) {\n\t\tconst exportList = match[1];\n\t\t// Skip if this looks like a type export (already handled above).\n\t\tif (content.substring(match.index - 5, match.index).includes(\"type\")) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst names = exportList.split(\",\").map((s) => {\n\t\t\tconst trimmed = s.trim();\n\t\t\tconst asMatch = trimmed.match(/(\\w+)\\s+as\\s+(\\w+)/);\n\t\t\tif (asMatch) {\n\t\t\t\treturn asMatch[2];\n\t\t\t}\n\t\t\tconst typeMatch = trimmed.match(/type\\s+(\\w+)/);\n\t\t\tif (typeMatch) {\n\t\t\t\treturn typeMatch[1];\n\t\t\t}\n\t\t\treturn trimmed;\n\t\t});\n\n\t\tfor (const name of names) {\n\t\t\tif (name && /^\\w+$/.test(name)) {\n\t\t\t\taddExport(name, \"unknown\");\n\t\t\t}\n\t\t}\n\t}\n\n\treturn exports;\n}\n\n/**\n * Get named exports from an installed package by parsing its type definitions.\n *\n * @param tmpDir - The temporary directory where the package is installed\n * @param packageName - The package name (e.g., \"@mantine/core\")\n * @returns ParsedExports containing the list of exports and count\n *\n */\nexport function getNamedExports(\n\ttmpDir: string,\n\tpackageName: string,\n): ParsedExports {\n\tconst packageDir = path.join(tmpDir, \"node_modules\", packageName);\n\n\tconst emptyResult: ParsedExports = {\n\t\texports: [],\n\t\tcount: 0,\n\t\truntimeExports: [],\n\t\truntimeCount: 0,\n\t};\n\n\t// Try to read package.json to find the types entry.\n\tconst pkgJsonPath = path.join(packageDir, \"package.json\");\n\tif (!fs.existsSync(pkgJsonPath)) {\n\t\treturn emptyResult;\n\t}\n\n\tlet typesEntry: string | undefined;\n\ttry {\n\t\tconst pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, \"utf-8\"));\n\n\t\t// Look for types in order of preference.\n\t\ttypesEntry =\n\t\t\tpkgJson.types ||\n\t\t\tpkgJson.typings ||\n\t\t\tpkgJson.exports?.[\".\"]?.types ||\n\t\t\t(typeof pkgJson.exports?.[\".\"] === \"object\" &&\n\t\t\t\tpkgJson.exports[\".\"].types);\n\n\t\t// If no types field, try common patterns.\n\t\tif (!typesEntry) {\n\t\t\tconst commonPaths = [\n\t\t\t\t\"dist/index.d.ts\",\n\t\t\t\t\"lib/index.d.ts\",\n\t\t\t\t\"index.d.ts\",\n\t\t\t\t\"types/index.d.ts\",\n\t\t\t];\n\t\t\tfor (const tryPath of commonPaths) {\n\t\t\t\tif (fs.existsSync(path.join(packageDir, tryPath))) {\n\t\t\t\t\ttypesEntry = tryPath;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn emptyResult;\n\t}\n\n\tif (!typesEntry) {\n\t\treturn emptyResult;\n\t}\n\n\t// Read and parse the types file.\n\tconst typesPath = path.join(packageDir, typesEntry);\n\tif (!fs.existsSync(typesPath)) {\n\t\treturn emptyResult;\n\t}\n\n\ttry {\n\t\tconst content = fs.readFileSync(typesPath, \"utf-8\");\n\t\tconst exports = parseDeclarationFile(typesPath, content);\n\n\t\t// Sort exports by name for consistent output.\n\t\texports.sort((a, b) => a.name.localeCompare(b.name));\n\n\t\t// Filter to runtime-only exports (exclude types and interfaces).\n\t\tconst runtimeExports = exports.filter(\n\t\t\t(e) => e.kind !== \"type\" && e.kind !== \"interface\",\n\t\t);\n\n\t\treturn {\n\t\t\texports,\n\t\t\tcount: exports.length,\n\t\t\truntimeExports,\n\t\t\truntimeCount: runtimeExports.length,\n\t\t};\n\t} catch {\n\t\treturn emptyResult;\n\t}\n}\n"],"names":["fs","path","resolveImportPath","basePath","importPath","cleanPath","replace","trim","startsWith","baseDir","dirname","resolved","resolve","extensions","ext","tryPath","existsSync","statSync","isFile","indexPath","join","parseDeclarationFile","filePath","content","visited","Set","depth","MAX_DEPTH","MAX_FILES","size","normalizedPath","has","add","exports","seenNames","addExport","name","kind","push","reExportAllPattern","reExportTypePattern","reExportValuePattern","functionPattern","classPattern","constPattern","typePattern","typePattern2","typeExportPattern","interfacePattern","enumPattern","namedExportPattern","componentPattern","functionPattern2","classPattern2","constPattern2","extractMatches","pattern","text","matches","result","exec","match","resolvedPath","importedContent","readFileSync","importedExports","exp","exportList","names","split","map","s","trimmed","asMatch","test","fullMatch","includes","typeMatch","substring","index","getNamedExports","tmpDir","packageName","packageDir","emptyResult","count","runtimeExports","runtimeCount","pkgJsonPath","typesEntry","pkgJson","JSON","parse","types","typings","commonPaths","typesPath","sort","a","b","localeCompare","filter","e","length"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export type GetBundleStatsOptions = {
|
|
|
27
27
|
*/
|
|
28
28
|
external?: string[];
|
|
29
29
|
/**
|
|
30
|
-
* Bundle everything including
|
|
30
|
+
* Bundle everything including dependencies that would normally be external.
|
|
31
31
|
*/
|
|
32
32
|
noExternal?: boolean;
|
|
33
33
|
/**
|
|
@@ -100,6 +100,11 @@ export type BundleStats = {
|
|
|
100
100
|
* Whether the result was retrieved from cache.
|
|
101
101
|
*/
|
|
102
102
|
fromCache: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Total number of named exports in the package (when analyzing entire
|
|
105
|
+
* package).
|
|
106
|
+
*/
|
|
107
|
+
namedExportCount: number;
|
|
103
108
|
};
|
|
104
109
|
/**
|
|
105
110
|
* Options for getting bundle size trend across versions.
|
|
@@ -122,7 +127,7 @@ export type GetBundleTrendOptions = {
|
|
|
122
127
|
*/
|
|
123
128
|
external?: string[];
|
|
124
129
|
/**
|
|
125
|
-
* Bundle everything including
|
|
130
|
+
* Bundle everything including dependencies that would normally be external.
|
|
126
131
|
*/
|
|
127
132
|
noExternal?: boolean;
|
|
128
133
|
/**
|
|
@@ -303,6 +308,80 @@ export declare function getBundleTrend(options: GetBundleTrendOptions): Promise<
|
|
|
303
308
|
*
|
|
304
309
|
*/
|
|
305
310
|
export declare function getPackageVersions(options: GetPackageVersionsOptions): Promise<PackageVersions>;
|
|
311
|
+
/**
|
|
312
|
+
* Options for getting package exports.
|
|
313
|
+
*/
|
|
314
|
+
export type GetPackageExportsOptions = {
|
|
315
|
+
/**
|
|
316
|
+
* Package name with optional version (e.g., "@mantine/core" or
|
|
317
|
+
* "@mantine/core@7.0.0").
|
|
318
|
+
*/
|
|
319
|
+
package: string;
|
|
320
|
+
/**
|
|
321
|
+
* Custom npm registry URL.
|
|
322
|
+
*/
|
|
323
|
+
registry?: string;
|
|
324
|
+
};
|
|
325
|
+
/**
|
|
326
|
+
* A named export from a package.
|
|
327
|
+
*/
|
|
328
|
+
export type PackageExport = {
|
|
329
|
+
/**
|
|
330
|
+
* The export name (e.g., "Button", "useState").
|
|
331
|
+
*/
|
|
332
|
+
name: string;
|
|
333
|
+
/**
|
|
334
|
+
* The type of export.
|
|
335
|
+
*/
|
|
336
|
+
kind: "function" | "class" | "const" | "type" | "interface" | "enum" | "unknown";
|
|
337
|
+
};
|
|
338
|
+
/**
|
|
339
|
+
* Result from getPackageExports.
|
|
340
|
+
*/
|
|
341
|
+
export type PackageExports = {
|
|
342
|
+
/**
|
|
343
|
+
* Package name.
|
|
344
|
+
*/
|
|
345
|
+
packageName: string;
|
|
346
|
+
/**
|
|
347
|
+
* Resolved package version.
|
|
348
|
+
*/
|
|
349
|
+
packageVersion: string;
|
|
350
|
+
/**
|
|
351
|
+
* Array of all named exports found in the package (including types).
|
|
352
|
+
*/
|
|
353
|
+
exports: PackageExport[];
|
|
354
|
+
/**
|
|
355
|
+
* Total count of all named exports (including types).
|
|
356
|
+
*/
|
|
357
|
+
count: number;
|
|
358
|
+
/**
|
|
359
|
+
* Array of runtime exports only (excluding types and interfaces). These are
|
|
360
|
+
* the exports that can actually be imported at runtime.
|
|
361
|
+
*/
|
|
362
|
+
runtimeExports: PackageExport[];
|
|
363
|
+
/**
|
|
364
|
+
* Count of runtime exports only (functions, classes, const, enums).
|
|
365
|
+
*/
|
|
366
|
+
runtimeCount: number;
|
|
367
|
+
};
|
|
368
|
+
/**
|
|
369
|
+
* Get the named exports of an npm package by analyzing its type definitions.
|
|
370
|
+
*
|
|
371
|
+
* @example
|
|
372
|
+
* ```js
|
|
373
|
+
* import { getPackageExports } from "@node-cli/bundlecheck";
|
|
374
|
+
*
|
|
375
|
+
* const { exports, count } = await getPackageExports({
|
|
376
|
+
* package: "@mantine/core@7.0.0",
|
|
377
|
+
* });
|
|
378
|
+
*
|
|
379
|
+
* console.log(`Found ${count} exports`);
|
|
380
|
+
* console.log(exports.map(e => e.name)); // ["Accordion", "ActionIcon", "Alert", ...]
|
|
381
|
+
* ```
|
|
382
|
+
*
|
|
383
|
+
*/
|
|
384
|
+
export declare function getPackageExports(options: GetPackageExportsOptions): Promise<PackageExports>;
|
|
306
385
|
/**
|
|
307
386
|
* =============================================================================
|
|
308
387
|
* Re-exports for advanced usage
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Programmatic interface for analyzing npm package bundle sizes.
|
|
5
5
|
*
|
|
6
|
-
*/ import { checkBundleSize, formatBytes,
|
|
6
|
+
*/ import { checkBundleSize, formatBytes, parsePackageSpecifier } from "./bundler.js";
|
|
7
7
|
import { getCachedResult, normalizeCacheKey, setCachedResult } from "./cache.js";
|
|
8
8
|
import { normalizePlatform, TREND_VERSION_COUNT } from "./defaults.js";
|
|
9
9
|
import { analyzeTrend, selectTrendVersions } from "./trend.js";
|
|
@@ -42,16 +42,18 @@ import { fetchPackageVersions as fetchVersions } from "./versions.js";
|
|
|
42
42
|
});
|
|
43
43
|
resolvedVersion = tags.latest || requestedVersion;
|
|
44
44
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Build cache key.
|
|
47
|
+
* NOTE: We use additionalExternals here, not computed externals, because the default externals (react, react-dom) are determined at bundle time based on the package's dependencies.
|
|
48
|
+
* The cache key captures the user's intent (additionalExternals + noExternal
|
|
49
|
+
* flag), and the actual externals are stored in the cached result.
|
|
50
|
+
*/ const cacheKey = normalizeCacheKey({
|
|
49
51
|
packageName: baseName,
|
|
50
52
|
version: resolvedVersion,
|
|
51
53
|
exports: exportsList,
|
|
52
54
|
platform,
|
|
53
55
|
gzipLevel,
|
|
54
|
-
externals,
|
|
56
|
+
externals: additionalExternals || [],
|
|
55
57
|
noExternal: noExternal ?? false
|
|
56
58
|
});
|
|
57
59
|
// Check cache (unless force is set).
|
|
@@ -190,6 +192,60 @@ import { fetchPackageVersions as fetchVersions } from "./versions.js";
|
|
|
190
192
|
tags: result.tags
|
|
191
193
|
};
|
|
192
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Get the named exports of an npm package by analyzing its type definitions.
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```js
|
|
200
|
+
* import { getPackageExports } from "@node-cli/bundlecheck";
|
|
201
|
+
*
|
|
202
|
+
* const { exports, count } = await getPackageExports({
|
|
203
|
+
* package: "@mantine/core@7.0.0",
|
|
204
|
+
* });
|
|
205
|
+
*
|
|
206
|
+
* console.log(`Found ${count} exports`);
|
|
207
|
+
* console.log(exports.map(e => e.name)); // ["Accordion", "ActionIcon", "Alert", ...]
|
|
208
|
+
* ```
|
|
209
|
+
*
|
|
210
|
+
*/ export async function getPackageExports(options) {
|
|
211
|
+
const { package: packageName, registry } = options;
|
|
212
|
+
/**
|
|
213
|
+
* Import the install utilities from bundler (we'll use a minimal bundle
|
|
214
|
+
* check).
|
|
215
|
+
*/ const { name: baseName, version: requestedVersion } = parsePackageSpecifier(packageName);
|
|
216
|
+
// Resolve "latest" to actual version.
|
|
217
|
+
let resolvedVersion = requestedVersion;
|
|
218
|
+
if (requestedVersion === "latest") {
|
|
219
|
+
const { tags } = await fetchVersions({
|
|
220
|
+
packageName: baseName,
|
|
221
|
+
registry
|
|
222
|
+
});
|
|
223
|
+
resolvedVersion = tags.latest || requestedVersion;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Use a minimal bundle check to install the package and get exports We'll
|
|
227
|
+
* leverage the existing infrastructure.
|
|
228
|
+
*/ const { installPackage } = await import("./exports-installer.js");
|
|
229
|
+
const { version, exports, runtimeExports } = await installPackage({
|
|
230
|
+
packageName: baseName,
|
|
231
|
+
version: resolvedVersion,
|
|
232
|
+
registry
|
|
233
|
+
});
|
|
234
|
+
return {
|
|
235
|
+
packageName: baseName,
|
|
236
|
+
packageVersion: version,
|
|
237
|
+
exports: exports.map((e)=>({
|
|
238
|
+
name: e.name,
|
|
239
|
+
kind: e.kind
|
|
240
|
+
})),
|
|
241
|
+
count: exports.length,
|
|
242
|
+
runtimeExports: runtimeExports.map((e)=>({
|
|
243
|
+
name: e.name,
|
|
244
|
+
kind: e.kind
|
|
245
|
+
})),
|
|
246
|
+
runtimeCount: runtimeExports.length
|
|
247
|
+
};
|
|
248
|
+
}
|
|
193
249
|
/**
|
|
194
250
|
* =============================================================================
|
|
195
251
|
* Re-exports for advanced usage
|
|
@@ -222,7 +278,8 @@ import { fetchPackageVersions as fetchVersions } from "./versions.js";
|
|
|
222
278
|
platform: result.platform,
|
|
223
279
|
rawSizeFormatted: formatBytes(result.rawSize),
|
|
224
280
|
gzipSizeFormatted: result.gzipSize !== null ? formatBytes(result.gzipSize) : null,
|
|
225
|
-
fromCache
|
|
281
|
+
fromCache,
|
|
282
|
+
namedExportCount: result.namedExportCount
|
|
226
283
|
};
|
|
227
284
|
}
|
|
228
285
|
|