Skip to content

Commit 95eda57

Browse files
Added a config property to toggle extensions on generated files based on expected compiled output extension of the file referenced in the apifile property. (#4743)
1 parent ff23771 commit 95eda57

File tree

3 files changed

+101
-6
lines changed

3 files changed

+101
-6
lines changed

packages/rtk-query-codegen-openapi/src/generate.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ export async function generateApi(
118118
mergeReadWriteOnly = false,
119119
httpResolverOptions,
120120
useUnknown = false,
121+
esmExtensions = false,
121122
}: GenerationOptions
122123
) {
123124
const v3Doc = (v3DocCache[spec] ??= await getV3Doc(spec, httpResolverOptions));
@@ -163,7 +164,17 @@ export async function generateApi(
163164
if (!apiFile.startsWith('.')) apiFile = `./${apiFile}`;
164165
}
165166
}
166-
apiFile = apiFile.replace(/\.[jt]sx?$/, '');
167+
168+
if (esmExtensions === true) {
169+
// Convert TS/JSX extensions to their JS equivalents
170+
apiFile = apiFile
171+
.replace(/\.mts$/, '.mjs')
172+
.replace(/\.[jt]sx$/, '.jsx')
173+
.replace(/\.ts$/, '.js');
174+
} else {
175+
// Remove all extensions
176+
apiFile = apiFile.replace(/\.[jt]sx?$/, '');
177+
}
167178

168179
return printer.printNode(
169180
ts.EmitHint.Unspecified,
@@ -451,11 +462,7 @@ export async function generateApi(
451462
const encodedValue =
452463
encodeQueryParams && param.param?.in === 'query'
453464
? factory.createConditionalExpression(
454-
factory.createBinaryExpression(
455-
value,
456-
ts.SyntaxKind.ExclamationEqualsToken,
457-
factory.createNull()
458-
),
465+
factory.createBinaryExpression(value, ts.SyntaxKind.ExclamationEqualsToken, factory.createNull()),
459466
undefined,
460467
factory.createCallExpression(factory.createIdentifier('encodeURIComponent'), undefined, [
461468
factory.createCallExpression(factory.createIdentifier('String'), undefined, [value]),

packages/rtk-query-codegen-openapi/src/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ export interface CommonOptions {
121121
* @since 2.1.0
122122
*/
123123
useUnknown?: boolean;
124+
/**
125+
* @default false
126+
* Will generate imports with file extension matching the expected compiled output of the api file
127+
*/
128+
esmExtensions?: boolean;
124129
}
125130

126131
export type TextMatcher = string | RegExp | (string | RegExp)[];

packages/rtk-query-codegen-openapi/test/generateEndpoints.test.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,3 +647,86 @@ describe('query parameters', () => {
647647
expect(api).toMatchSnapshot();
648648
});
649649
});
650+
651+
describe('esmExtensions option', () => {
652+
beforeAll(async () => {
653+
if (!(await isDir(tmpDir))) {
654+
await fs.mkdir(tmpDir, { recursive: true });
655+
}
656+
});
657+
658+
afterEach(async () => {
659+
await rimraf(`${tmpDir}/*.ts`, { glob: true });
660+
});
661+
662+
test('should convert .ts to .js when esmExtensions is true', async () => {
663+
await generateEndpoints({
664+
apiFile: './fixtures/emptyApi.ts',
665+
outputFile: './test/tmp/out.ts',
666+
schemaFile: resolve(__dirname, 'fixtures/petstore.json'),
667+
filterEndpoints: [],
668+
esmExtensions: true,
669+
});
670+
const content = await fs.readFile('./test/tmp/out.ts', 'utf8');
671+
expect(content).toContain("import { api } from '../../fixtures/emptyApi.js'");
672+
});
673+
674+
test('should convert .mts to .mjs when esmExtensions is true', async () => {
675+
await generateEndpoints({
676+
apiFile: './fixtures/emptyApi.mts',
677+
outputFile: './test/tmp/out.ts',
678+
schemaFile: resolve(__dirname, 'fixtures/petstore.json'),
679+
filterEndpoints: [],
680+
esmExtensions: true,
681+
});
682+
const content = await fs.readFile('./test/tmp/out.ts', 'utf8');
683+
expect(content).toContain("import { api } from '../../fixtures/emptyApi.mjs'");
684+
});
685+
686+
test('should preserve .jsx when esmExtensions is true', async () => {
687+
await generateEndpoints({
688+
apiFile: './fixtures/emptyApi.jsx',
689+
outputFile: './test/tmp/out.ts',
690+
schemaFile: resolve(__dirname, 'fixtures/petstore.json'),
691+
filterEndpoints: [],
692+
esmExtensions: true,
693+
});
694+
const content = await fs.readFile('./test/tmp/out.ts', 'utf8');
695+
expect(content).toContain("import { api } from '../../fixtures/emptyApi.jsx'");
696+
});
697+
698+
test('should convert .tsx to .jsx when esmExtensions is true', async () => {
699+
await generateEndpoints({
700+
apiFile: './fixtures/emptyApi.tsx',
701+
outputFile: './test/tmp/out.ts',
702+
schemaFile: resolve(__dirname, 'fixtures/petstore.json'),
703+
filterEndpoints: [],
704+
esmExtensions: true,
705+
});
706+
const content = await fs.readFile('./test/tmp/out.ts', 'utf8');
707+
expect(content).toContain("import { api } from '../../fixtures/emptyApi.jsx'");
708+
});
709+
710+
test('should strip extensions when esmExtensions is false', async () => {
711+
await generateEndpoints({
712+
apiFile: './fixtures/emptyApi.ts',
713+
outputFile: './test/tmp/out.ts',
714+
schemaFile: resolve(__dirname, 'fixtures/petstore.json'),
715+
filterEndpoints: [],
716+
esmExtensions: false,
717+
});
718+
const content = await fs.readFile('./test/tmp/out.ts', 'utf8');
719+
expect(content).toContain("import { api } from '../../fixtures/emptyApi'");
720+
});
721+
722+
test('should strip extensions when esmExtensions is undefined (default)', async () => {
723+
await generateEndpoints({
724+
apiFile: './fixtures/emptyApi.ts',
725+
outputFile: './test/tmp/out.ts',
726+
schemaFile: resolve(__dirname, 'fixtures/petstore.json'),
727+
filterEndpoints: [],
728+
});
729+
const content = await fs.readFile('./test/tmp/out.ts', 'utf8');
730+
expect(content).toContain("import { api } from '../../fixtures/emptyApi'");
731+
});
732+
});

0 commit comments

Comments
 (0)