fork of hey-api/openapi-ts because I need some additional things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #3380 from hey-api/copilot/fix-implicit-module-resolution

Detect implicit moduleResolution from module compiler option

authored by

Lubos and committed by
GitHub
a2ad2aa4 e57fdde3

+188 -1
+5
.changeset/little-lobsters-think.md
··· 1 + --- 2 + "@hey-api/openapi-ts": patch 3 + --- 4 + 5 + **output**: detect `importFileExtension` from tsconfig `module` option
+180
packages/openapi-ts/src/config/output/__tests__/config.test.ts
··· 1 + import fs from 'node:fs'; 2 + import os from 'node:os'; 3 + import path from 'node:path'; 4 + 5 + import { getOutput } from '../config'; 6 + 7 + describe('getOutput', () => { 8 + let tmpDir: string; 9 + 10 + beforeEach(() => { 11 + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'openapi-ts-test-')); 12 + }); 13 + 14 + afterEach(() => { 15 + if (fs.existsSync(tmpDir)) { 16 + fs.rmSync(tmpDir, { force: true, recursive: true }); 17 + } 18 + }); 19 + 20 + describe('module resolution detection', () => { 21 + it('should set importFileExtension when moduleResolution is NodeNext', () => { 22 + const tsconfigPath = path.join(tmpDir, 'tsconfig.json'); 23 + fs.writeFileSync( 24 + tsconfigPath, 25 + JSON.stringify({ 26 + compilerOptions: { 27 + moduleResolution: 'nodenext', 28 + }, 29 + }), 30 + ); 31 + 32 + const output = getOutput({ 33 + output: { 34 + path: tmpDir, 35 + tsConfigPath: tsconfigPath, 36 + }, 37 + }); 38 + 39 + expect(output.importFileExtension).toBe('.js'); 40 + }); 41 + 42 + it('should set importFileExtension when moduleResolution is Node16', () => { 43 + const tsconfigPath = path.join(tmpDir, 'tsconfig.json'); 44 + fs.writeFileSync( 45 + tsconfigPath, 46 + JSON.stringify({ 47 + compilerOptions: { 48 + moduleResolution: 'node16', 49 + }, 50 + }), 51 + ); 52 + 53 + const output = getOutput({ 54 + output: { 55 + path: tmpDir, 56 + tsConfigPath: tsconfigPath, 57 + }, 58 + }); 59 + 60 + expect(output.importFileExtension).toBe('.js'); 61 + }); 62 + 63 + it('should set importFileExtension when module is NodeNext (implicit moduleResolution)', () => { 64 + const tsconfigPath = path.join(tmpDir, 'tsconfig.json'); 65 + fs.writeFileSync( 66 + tsconfigPath, 67 + JSON.stringify({ 68 + compilerOptions: { 69 + module: 'nodenext', 70 + }, 71 + }), 72 + ); 73 + 74 + const output = getOutput({ 75 + output: { 76 + path: tmpDir, 77 + tsConfigPath: tsconfigPath, 78 + }, 79 + }); 80 + 81 + expect(output.importFileExtension).toBe('.js'); 82 + }); 83 + 84 + it('should set importFileExtension when module is Node16 (implicit moduleResolution)', () => { 85 + const tsconfigPath = path.join(tmpDir, 'tsconfig.json'); 86 + fs.writeFileSync( 87 + tsconfigPath, 88 + JSON.stringify({ 89 + compilerOptions: { 90 + module: 'node16', 91 + }, 92 + }), 93 + ); 94 + 95 + const output = getOutput({ 96 + output: { 97 + path: tmpDir, 98 + tsConfigPath: tsconfigPath, 99 + }, 100 + }); 101 + 102 + expect(output.importFileExtension).toBe('.js'); 103 + }); 104 + 105 + it('should not set importFileExtension for other module types', () => { 106 + const tsconfigPath = path.join(tmpDir, 'tsconfig.json'); 107 + fs.writeFileSync( 108 + tsconfigPath, 109 + JSON.stringify({ 110 + compilerOptions: { 111 + module: 'esnext', 112 + }, 113 + }), 114 + ); 115 + 116 + const output = getOutput({ 117 + output: { 118 + path: tmpDir, 119 + tsConfigPath: tsconfigPath, 120 + }, 121 + }); 122 + 123 + expect(output.importFileExtension).toBeUndefined(); 124 + }); 125 + 126 + it('should not override explicit importFileExtension setting', () => { 127 + const tsconfigPath = path.join(tmpDir, 'tsconfig.json'); 128 + fs.writeFileSync( 129 + tsconfigPath, 130 + JSON.stringify({ 131 + compilerOptions: { 132 + module: 'nodenext', 133 + }, 134 + }), 135 + ); 136 + 137 + const output = getOutput({ 138 + output: { 139 + importFileExtension: '.ts', 140 + path: tmpDir, 141 + tsConfigPath: tsconfigPath, 142 + }, 143 + }); 144 + 145 + expect(output.importFileExtension).toBe('.ts'); 146 + }); 147 + 148 + it('should work when both module and moduleResolution are set', () => { 149 + const tsconfigPath = path.join(tmpDir, 'tsconfig.json'); 150 + fs.writeFileSync( 151 + tsconfigPath, 152 + JSON.stringify({ 153 + compilerOptions: { 154 + module: 'nodenext', 155 + moduleResolution: 'nodenext', 156 + }, 157 + }), 158 + ); 159 + 160 + const output = getOutput({ 161 + output: { 162 + path: tmpDir, 163 + tsConfigPath: tsconfigPath, 164 + }, 165 + }); 166 + 167 + expect(output.importFileExtension).toBe('.js'); 168 + }); 169 + 170 + it('should handle missing tsconfig gracefully', () => { 171 + const output = getOutput({ 172 + output: { 173 + path: tmpDir, 174 + }, 175 + }); 176 + 177 + expect(output.importFileExtension).toBeUndefined(); 178 + }); 179 + }); 180 + });
+3 -1
packages/openapi-ts/src/config/output/config.ts
··· 65 65 if ( 66 66 output.importFileExtension === undefined && 67 67 (output.tsConfig?.options.moduleResolution === ts.ModuleResolutionKind.NodeNext || 68 - output.tsConfig?.options.moduleResolution === ts.ModuleResolutionKind.Node16) 68 + output.tsConfig?.options.moduleResolution === ts.ModuleResolutionKind.Node16 || 69 + output.tsConfig?.options.module === ts.ModuleKind.NodeNext || 70 + output.tsConfig?.options.module === ts.ModuleKind.Node16) 69 71 ) { 70 72 output.importFileExtension = '.js'; 71 73 }