Skip to content

Commit f059ad9

Browse files
fix: add .js extensions to declaration file imports to resolve type re-export issue (#410)
Co-authored-by: Claude <[email protected]>
1 parent 27d6133 commit f059ad9

File tree

2 files changed

+129
-2
lines changed

2 files changed

+129
-2
lines changed

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@
3333
"build:cjs": "npx tsc -p tsconfig.cjs.json",
3434
"build:esm": "npx tsc -p tsconfig.esm.json",
3535
"build:fix-esm": "node scripts/fix-esm-imports.cjs",
36+
"build:fix-dts": "node scripts/fix-dts-imports.cjs",
3637
"build:post": "echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
37-
"build": "npm-run-all clean build:cjs build:esm build:fix-esm build:post",
38-
"integrity-checks": "npm-run-all clean format-check lint-check test build",
38+
"build": "npm-run-all clean build:cjs build:esm build:fix-esm build:fix-dts build:post",
39+
"attw": "npx @arethetypeswrong/cli --pack --ignore-rules fallback-condition false-esm",
40+
"integrity-checks": "npm-run-all clean format-check lint-check test build attw",
3941
"prepublishOnly": "npm run integrity-checks",
4042
"prepare": "npm run build"
4143
},

scripts/fix-dts-imports.cjs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#!/usr/bin/env node
2+
3+
const fs = require('fs');
4+
const path = require('path');
5+
6+
/**
7+
* Post-build script to fix TypeScript declaration file imports by adding .js extensions.
8+
* This is required because when package.json has "type": "module", TypeScript treats
9+
* .d.ts files as ESM modules, which require explicit file extensions for relative imports.
10+
*/
11+
12+
const TYPES_DIR = path.join(__dirname, '../dist/types');
13+
14+
function fixImportsInFile(filePath) {
15+
let content = fs.readFileSync(filePath, 'utf8');
16+
let modified = false;
17+
18+
// Fix relative imports - add .js extension if missing
19+
content = content.replace(
20+
/from\s+['"](\.[^'"]*?)['"];?/g,
21+
(match, importPath) => {
22+
// Skip if already has extension or is directory import
23+
if (path.extname(importPath) || importPath.endsWith('/')) {
24+
return match;
25+
}
26+
27+
// Check if this is a directory import (look for index file)
28+
const fullPath = path.resolve(path.dirname(filePath), importPath);
29+
const indexPath = path.join(fullPath, 'index.d.ts');
30+
31+
if (fs.existsSync(indexPath)) {
32+
// Directory import - add /index.js
33+
modified = true;
34+
return match.replace(importPath, importPath + '/index.js');
35+
} else {
36+
// File import - add .js
37+
modified = true;
38+
return match.replace(importPath, importPath + '.js');
39+
}
40+
}
41+
);
42+
43+
// Fix export statements as well
44+
content = content.replace(
45+
/export\s+(?:\*|\{[^}]*\})\s+from\s+['"](\.[^'"]*?)['"];?/g,
46+
(match, importPath) => {
47+
// Skip if already has extension or is directory import
48+
if (path.extname(importPath) || importPath.endsWith('/')) {
49+
return match;
50+
}
51+
52+
// Check if this is a directory import (look for index file)
53+
const fullPath = path.resolve(path.dirname(filePath), importPath);
54+
const indexPath = path.join(fullPath, 'index.d.ts');
55+
56+
if (fs.existsSync(indexPath)) {
57+
// Directory import - add /index.js
58+
modified = true;
59+
return match.replace(importPath, importPath + '/index.js');
60+
} else {
61+
// File import - add .js
62+
modified = true;
63+
return match.replace(importPath, importPath + '.js');
64+
}
65+
}
66+
);
67+
68+
// Fix dynamic import() type expressions
69+
content = content.replace(
70+
/import\(['"](\.[^'"]*?)['"]\)/g,
71+
(match, importPath) => {
72+
// Skip if already has extension or is directory import
73+
if (path.extname(importPath) || importPath.endsWith('/')) {
74+
return match;
75+
}
76+
77+
// Check if this is a directory import (look for index file)
78+
const fullPath = path.resolve(path.dirname(filePath), importPath);
79+
const indexPath = path.join(fullPath, 'index.d.ts');
80+
81+
if (fs.existsSync(indexPath)) {
82+
// Directory import - add /index.js
83+
modified = true;
84+
return match.replace(importPath, importPath + '/index.js');
85+
} else {
86+
// File import - add .js
87+
modified = true;
88+
return match.replace(importPath, importPath + '.js');
89+
}
90+
}
91+
);
92+
93+
if (modified) {
94+
fs.writeFileSync(filePath, content, 'utf8');
95+
console.log(`Fixed imports in: ${path.relative(process.cwd(), filePath)}`);
96+
}
97+
}
98+
99+
function walkDirectory(dir) {
100+
const files = fs.readdirSync(dir);
101+
102+
for (const file of files) {
103+
const filePath = path.join(dir, file);
104+
const stat = fs.statSync(filePath);
105+
106+
if (stat.isDirectory()) {
107+
walkDirectory(filePath);
108+
} else if (file.endsWith('.d.ts')) {
109+
fixImportsInFile(filePath);
110+
}
111+
}
112+
}
113+
114+
function main() {
115+
if (!fs.existsSync(TYPES_DIR)) {
116+
console.log('Types directory does not exist, skipping declaration file fixing');
117+
return;
118+
}
119+
120+
console.log('Fixing TypeScript declaration file imports by adding .js extensions...');
121+
walkDirectory(TYPES_DIR);
122+
console.log('Declaration file import fixing completed');
123+
}
124+
125+
main();

0 commit comments

Comments
 (0)