Skip to content

Commit 73fbadb

Browse files
committed
feat: support custom codec files in host repositories
DX-658
1 parent aa52270 commit 73fbadb

File tree

7 files changed

+158
-2
lines changed

7 files changed

+158
-2
lines changed

packages/openapi-generator/src/project.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export class Project {
3737
async parseEntryPoint(entryPoint: string): Promise<E.Either<string, Project>> {
3838
const queue: string[] = [entryPoint];
3939
let path: string | undefined;
40+
const visitedPackages = new Set<string>();
4041
while (((path = queue.pop()), path !== undefined)) {
4142
if (!['.ts', '.js'].includes(p.extname(path))) {
4243
continue;
@@ -59,6 +60,14 @@ export class Project {
5960
// If we are not resolving a relative path, we need to resolve the entry point
6061
const baseDir = p.dirname(sourceFile.path);
6162
let entryPoint = this.resolveEntryPoint(baseDir, sym.from);
63+
64+
if (!visitedPackages.has(sym.from)) {
65+
// This is a step that checks if this import has custom codecs, and loads them into known imports
66+
await this.populateCustomCodecs(baseDir, sym.from);
67+
}
68+
69+
visitedPackages.add(sym.from);
70+
6271
if (E.isLeft(entryPoint)) {
6372
continue;
6473
} else if (!this.has(entryPoint.right)) {
@@ -148,4 +157,40 @@ export class Project {
148157
getTypes() {
149158
return this.types;
150159
}
160+
161+
private async populateCustomCodecs(basedir: string, packageName: string) {
162+
try {
163+
const packageJson = resolve.sync(`${packageName}/package.json`, {
164+
basedir,
165+
extensions: ['.json'],
166+
});
167+
const packageInfo = JSON.parse(fs.readFileSync(packageJson, 'utf8'));
168+
169+
if (packageInfo['customCodecFile']) {
170+
// The package defines their own custom codecs
171+
const customCodecPath = resolve.sync(
172+
`${packageName}/${packageInfo['customCodecFile']}`,
173+
{
174+
basedir,
175+
extensions: ['.ts', '.js'],
176+
},
177+
);
178+
const module = await import(customCodecPath);
179+
if (module.default === undefined) {
180+
console.error(`Could not find default export in ${customCodecPath}`);
181+
return;
182+
}
183+
184+
const customCodecs = module.default(E);
185+
this.knownImports[packageName] = {
186+
...this.knownImports[packageName],
187+
...customCodecs,
188+
};
189+
190+
console.error(`Loaded custom codecs for ${packageName}`);
191+
}
192+
} catch (e) {
193+
return;
194+
}
195+
}
151196
}

packages/openapi-generator/test/externalModuleApiSpec.test.ts

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ async function testCase(
126126
components,
127127
);
128128

129-
assert.deepEqual(errors, expectedErrors);
130-
assert.deepEqual(openapi, expected);
129+
assert.deepStrictEqual(errors, expectedErrors);
130+
assert.deepStrictEqual(openapi, expected);
131131
});
132132
}
133133

@@ -319,3 +319,48 @@ testCase(
319319
},
320320
[]
321321
)
322+
323+
testCase("simple api spec with custom codec", "test/sample-types/apiSpecWithCustomCodec.ts", {
324+
openapi: "3.0.3",
325+
info: {
326+
title: "simple api spec with custom codec",
327+
version: "4.7.4",
328+
description: "simple api spec with custom codec"
329+
},
330+
paths: {
331+
"/test": {
332+
get: {
333+
parameters: [],
334+
responses: {
335+
200: {
336+
description: "OK",
337+
content: {
338+
'application/json': {
339+
schema: {
340+
type: 'string',
341+
description: 'Sample custom codec',
342+
example: 'sample',
343+
format: 'sample'
344+
}
345+
}
346+
}
347+
},
348+
201: {
349+
description: 'Created',
350+
content: {
351+
'application/json': {
352+
schema: {
353+
type: 'number',
354+
description: 'Another sample codec',
355+
}
356+
}
357+
}
358+
}
359+
}
360+
}
361+
}
362+
},
363+
components: {
364+
schemas: {}
365+
}
366+
}, []);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { SampleCustomCodec, AnotherSampleCodec } from '@bitgo/custom-codecs';
2+
import * as h from '@api-ts/io-ts-http';
3+
4+
export const apiSpec = h.apiSpec({
5+
'api.get.test': {
6+
get: h.httpRoute({
7+
path: '/test',
8+
method: 'GET',
9+
request: h.httpRequest({}),
10+
response: {
11+
200: SampleCustomCodec,
12+
201: AnotherSampleCodec,
13+
},
14+
}),
15+
},
16+
})

packages/openapi-generator/test/sample-types/node_modules/@bitgo/custom-codecs/openapi-gen.config.js

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

packages/openapi-generator/test/sample-types/node_modules/@bitgo/custom-codecs/package.json

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

packages/openapi-generator/test/sample-types/node_modules/@bitgo/custom-codecs/src/index.ts

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

packages/openapi-generator/test/sample-types/node_modules/@bitgo/custom-codecs/tsconfig.json

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

0 commit comments

Comments
 (0)