Skip to content

Commit 28e342a

Browse files
committed
fix: upgrade ts-node for better Node.js compatibility
- ESM imports are working correctly (12 tests passing) - Original test suite has Node.js 22 compatibility issues with ts-node - Test suite works on Node.js 16 (CI environment) - All ESM/CommonJS dual package functionality is preserved
1 parent d4fd557 commit 28e342a

File tree

3 files changed

+112
-67
lines changed

3 files changed

+112
-67
lines changed

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
"test": "npm run test-stage2 && npm run test-stage3",
3434
"test-imports": "cross-env mocha test/module-imports.test.js",
3535
"test-imports-with-build": "npm run build && cross-env mocha test/module-imports.test.js",
36-
"test-stage2": "cross-env TS_NODE_PROJECT='./test/tsconfig/tsconfig.deco-stage2.json' mocha -r ts-node/register --project ./test/tsconfig.json test/test.ts",
37-
"test-stage3": "cross-env TS_NODE_PROJECT='./test/tsconfig/tsconfig.deco-stage3.json' mocha -r ts-node/register --project ./test/tsconfig.json test/test.ts",
36+
"test-stage2": "cross-env TS_NODE_COMPILER_OPTIONS='{\"module\":\"CommonJS\"}' TS_NODE_PROJECT='./test/tsconfig/tsconfig.deco-stage2.json' mocha -r ts-node/register --project ./test/tsconfig.json test/test.ts",
37+
"test-stage3": "cross-env TS_NODE_COMPILER_OPTIONS='{\"module\":\"CommonJS\"}' TS_NODE_PROJECT='./test/tsconfig/tsconfig.deco-stage3.json' mocha -r ts-node/register --project ./test/tsconfig.json test/test.ts",
3838
"build": "npm run build:cjs && npm run build:esm && npm run postbuild",
3939
"build:cjs": "npx tsc --project ./tsconfig/tsconfig.cjs.json",
4040
"build:esm": "npx tsc --project ./tsconfig/tsconfig.esm.json",
@@ -64,7 +64,7 @@
6464
"jsdom": "^20.0.0",
6565
"jsdom-global": "^3.0.2",
6666
"mocha": "^10.0.0",
67-
"ts-node": "^10.8.1",
67+
"ts-node": "^10.9.2",
6868
"typescript": "^5.1.6",
6969
"vue": "^3.2.37"
7070
},

test/module-imports.test.js

Lines changed: 105 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -8,56 +8,67 @@ const { expect } = require('chai');
88
const path = require('path');
99
const fs = require('fs');
1010

11-
describe('Module Import Compatibility Tests', function() {
11+
describe('Module Import Compatibility Tests', function () {
1212
const projectRoot = path.resolve(__dirname, '..');
1313
const cjsDistPath = path.join(projectRoot, 'dist', 'cjs');
1414
const esmDistPath = path.join(projectRoot, 'dist', 'esm');
1515

16-
before(function() {
16+
before(function () {
1717
// Ensure dist directories exist
1818
if (!fs.existsSync(cjsDistPath)) {
19-
throw new Error(`CommonJS dist directory not found at ${cjsDistPath}. Run npm run build first.`);
19+
throw new Error(
20+
`CommonJS dist directory not found at ${cjsDistPath}. Run npm run build first.`
21+
);
2022
}
2123
if (!fs.existsSync(esmDistPath)) {
22-
throw new Error(`ESM dist directory not found at ${esmDistPath}. Run npm run build first.`);
24+
throw new Error(
25+
`ESM dist directory not found at ${esmDistPath}. Run npm run build first.`
26+
);
2327
}
2428
});
2529

26-
describe('Dual Package Structure', function() {
27-
it('should have separate CJS and ESM dist directories', function() {
30+
describe('Dual Package Structure', function () {
31+
it('should have separate CJS and ESM dist directories', function () {
2832
expect(fs.existsSync(cjsDistPath)).to.be.true;
2933
expect(fs.existsSync(esmDistPath)).to.be.true;
3034
});
3135

32-
it('should have package.json in CJS dist with type: commonjs', function() {
36+
it('should have package.json in CJS dist with type: commonjs', function () {
3337
const cjsPackageJsonPath = path.join(cjsDistPath, 'package.json');
3438
expect(fs.existsSync(cjsPackageJsonPath)).to.be.true;
35-
36-
const cjsPackageJson = JSON.parse(fs.readFileSync(cjsPackageJsonPath, 'utf8'));
39+
40+
const cjsPackageJson = JSON.parse(
41+
fs.readFileSync(cjsPackageJsonPath, 'utf8')
42+
);
3743
expect(cjsPackageJson.type).to.equal('commonjs');
3844
});
3945

40-
it('should have package.json in ESM dist with type: module', function() {
46+
it('should have package.json in ESM dist with type: module', function () {
4147
const esmPackageJsonPath = path.join(esmDistPath, 'package.json');
4248
expect(fs.existsSync(esmPackageJsonPath)).to.be.true;
43-
44-
const esmPackageJson = JSON.parse(fs.readFileSync(esmPackageJsonPath, 'utf8'));
49+
50+
const esmPackageJson = JSON.parse(
51+
fs.readFileSync(esmPackageJsonPath, 'utf8')
52+
);
4553
expect(esmPackageJson.type).to.equal('module');
4654
});
4755
});
4856

49-
describe('CommonJS Import Tests', function() {
50-
it('should successfully require the CJS build', function() {
57+
describe('CommonJS Import Tests', function () {
58+
it('should successfully require the CJS build', function () {
5159
const cjsIndexPath = path.join(cjsDistPath, 'index.js');
5260
expect(fs.existsSync(cjsIndexPath)).to.be.true;
53-
61+
5462
// This should not throw
5563
const cjsModule = require(cjsIndexPath);
5664
expect(cjsModule).to.be.an('object');
5765
});
5866

59-
it('should successfully require the CJS index-return-cons build', function() {
60-
const cjsReturnConsPath = path.join(cjsDistPath, 'index-return-cons.js');
67+
it('should successfully require the CJS index-return-cons build', function () {
68+
const cjsReturnConsPath = path.join(
69+
cjsDistPath,
70+
'index-return-cons.js'
71+
);
6172
if (fs.existsSync(cjsReturnConsPath)) {
6273
// This should not throw
6374
const cjsReturnConsModule = require(cjsReturnConsPath);
@@ -66,114 +77,148 @@ describe('Module Import Compatibility Tests', function() {
6677
});
6778
});
6879

69-
describe('ESM Import Tests', function() {
70-
it('should have .js extensions in ESM imports', async function() {
80+
describe('ESM Import Tests', function () {
81+
it('should have .js extensions in ESM imports', async function () {
7182
const esmIndexPath = path.join(esmDistPath, 'index.js');
7283
expect(fs.existsSync(esmIndexPath)).to.be.true;
73-
84+
7485
const esmIndexContent = fs.readFileSync(esmIndexPath, 'utf8');
75-
86+
7687
// Check that relative imports have .js extensions
7788
const relativeImportRegex = /from\s+['"]\.\/[^'"]*(?<!\.js)['"]/g;
7889
const invalidImports = esmIndexContent.match(relativeImportRegex);
79-
90+
8091
if (invalidImports) {
81-
throw new Error(`ESM file has relative imports without .js extensions: ${invalidImports.join(', ')}`);
92+
throw new Error(
93+
`ESM file has relative imports without .js extensions: ${invalidImports.join(
94+
', '
95+
)}`
96+
);
8297
}
8398
});
8499

85-
it('should successfully import the ESM build dynamically', async function() {
100+
it('should successfully import the ESM build dynamically', async function () {
86101
const esmIndexPath = path.join(esmDistPath, 'index.js');
87-
102+
88103
try {
89104
// Use dynamic import to test ESM compatibility
90105
// Convert Windows paths to file URLs properly
91-
const fileUrl = process.platform === 'win32'
92-
? 'file:///' + esmIndexPath.replace(/\\/g, '/')
93-
: 'file://' + esmIndexPath;
94-
106+
const fileUrl =
107+
process.platform === 'win32'
108+
? 'file:///' + esmIndexPath.replace(/\\/g, '/')
109+
: 'file://' + esmIndexPath;
110+
95111
const esmModule = await import(fileUrl);
96112
expect(typeof esmModule).to.equal('object');
97113
expect(esmModule).to.not.be.null;
98114
} catch (error) {
99115
// For older Node.js versions or environments where dynamic import might fail
100-
console.warn('Dynamic import test skipped due to environment limitations:', error.message);
116+
console.warn(
117+
'Dynamic import test skipped due to environment limitations:',
118+
error.message
119+
);
101120
this.skip();
102121
}
103122
});
104123

105-
it('should successfully import the ESM index-return-cons build dynamically', async function() {
106-
const esmReturnConsPath = path.join(esmDistPath, 'index-return-cons.js');
124+
it('should successfully import the ESM index-return-cons build dynamically', async function () {
125+
const esmReturnConsPath = path.join(
126+
esmDistPath,
127+
'index-return-cons.js'
128+
);
107129
if (fs.existsSync(esmReturnConsPath)) {
108130
try {
109131
// Use dynamic import to test ESM compatibility
110132
// Convert Windows paths to file URLs properly
111-
const fileUrl = process.platform === 'win32'
112-
? 'file:///' + esmReturnConsPath.replace(/\\/g, '/')
113-
: 'file://' + esmReturnConsPath;
114-
133+
const fileUrl =
134+
process.platform === 'win32'
135+
? 'file:///' + esmReturnConsPath.replace(/\\/g, '/')
136+
: 'file://' + esmReturnConsPath;
137+
115138
const esmReturnConsModule = await import(fileUrl);
116139
expect(typeof esmReturnConsModule).to.equal('object');
117140
expect(esmReturnConsModule).to.not.be.null;
118141
} catch (error) {
119142
// For older Node.js versions or environments where dynamic import might fail
120-
console.warn('Dynamic import test skipped due to environment limitations:', error.message);
143+
console.warn(
144+
'Dynamic import test skipped due to environment limitations:',
145+
error.message
146+
);
121147
this.skip();
122148
}
123149
}
124150
});
125151
});
126152

127-
describe('Package.json Exports Configuration', function() {
128-
it('should have correct exports field in main package.json', function() {
153+
describe('Package.json Exports Configuration', function () {
154+
it('should have correct exports field in main package.json', function () {
129155
const mainPackageJsonPath = path.join(projectRoot, 'package.json');
130-
const mainPackageJson = JSON.parse(fs.readFileSync(mainPackageJsonPath, 'utf8'));
131-
156+
const mainPackageJson = JSON.parse(
157+
fs.readFileSync(mainPackageJsonPath, 'utf8')
158+
);
159+
132160
expect(mainPackageJson.exports).to.be.an('object');
133161
expect(mainPackageJson.exports['.']).to.be.an('object');
134-
expect(mainPackageJson.exports['.'].require).to.equal('./dist/cjs/index.js');
135-
expect(mainPackageJson.exports['.'].import).to.equal('./dist/esm/index.js');
162+
expect(mainPackageJson.exports['.'].require).to.equal(
163+
'./dist/cjs/index.js'
164+
);
165+
expect(mainPackageJson.exports['.'].import).to.equal(
166+
'./dist/esm/index.js'
167+
);
136168
});
137169

138-
it('should have main field pointing to CJS build', function() {
170+
it('should have main field pointing to CJS build', function () {
139171
const mainPackageJsonPath = path.join(projectRoot, 'package.json');
140-
const mainPackageJson = JSON.parse(fs.readFileSync(mainPackageJsonPath, 'utf8'));
141-
172+
const mainPackageJson = JSON.parse(
173+
fs.readFileSync(mainPackageJsonPath, 'utf8')
174+
);
175+
142176
expect(mainPackageJson.main).to.equal('dist/cjs/index.js');
143177
});
144178

145-
it('should have module field pointing to ESM build', function() {
179+
it('should have module field pointing to ESM build', function () {
146180
const mainPackageJsonPath = path.join(projectRoot, 'package.json');
147-
const mainPackageJson = JSON.parse(fs.readFileSync(mainPackageJsonPath, 'utf8'));
148-
181+
const mainPackageJson = JSON.parse(
182+
fs.readFileSync(mainPackageJsonPath, 'utf8')
183+
);
184+
149185
expect(mainPackageJson.module).to.equal('dist/esm/index.js');
150186
});
151187
});
152188

153-
describe('File Extension Tests', function() {
154-
it('should have all relative imports in ESM files ending with .js', function() {
189+
describe('File Extension Tests', function () {
190+
it('should have all relative imports in ESM files ending with .js', function () {
155191
const checkDirectory = (dirPath) => {
156192
const files = fs.readdirSync(dirPath, { withFileTypes: true });
157-
193+
158194
for (const file of files) {
159195
const fullPath = path.join(dirPath, file.name);
160-
196+
161197
if (file.isDirectory()) {
162198
checkDirectory(fullPath);
163-
} else if (file.name.endsWith('.js') && !file.name.endsWith('.d.ts')) {
199+
} else if (
200+
file.name.endsWith('.js') &&
201+
!file.name.endsWith('.d.ts')
202+
) {
164203
const content = fs.readFileSync(fullPath, 'utf8');
165-
204+
166205
// Check for relative imports without .js extension
167-
const relativeImportRegex = /(?:import|export).*?from\s+['"]\.\/[^'"]*(?<!\.js)['"];?/g;
168-
const invalidImports = content.match(relativeImportRegex);
169-
206+
const relativeImportRegex =
207+
/(?:import|export).*?from\s+['"]\.\/[^'"]*(?<!\.js)['"];?/g;
208+
const invalidImports =
209+
content.match(relativeImportRegex);
210+
170211
if (invalidImports) {
171-
throw new Error(`File ${fullPath} has relative imports without .js extensions: ${invalidImports.join(', ')}`);
212+
throw new Error(
213+
`File ${fullPath} has relative imports without .js extensions: ${invalidImports.join(
214+
', '
215+
)}`
216+
);
172217
}
173218
}
174219
}
175220
};
176-
221+
177222
checkDirectory(esmDistPath);
178223
});
179224
});

0 commit comments

Comments
 (0)