Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/openapi-generator/src/codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function codecIdentifier(
} else if (imp.type === 'star') {
return E.left(`Tried to use star import as codec ${id.value}`);
}
const knownImport = project.knownImports[imp.from]?.[imp.importedName];
const knownImport = project.resolveKnownImport(imp.from, imp.importedName);
if (knownImport !== undefined) {
return E.right({ type: 'codec', schema: knownImport });
}
Expand Down Expand Up @@ -67,7 +67,7 @@ function codecIdentifier(
}

const name = id.property.value;
const knownImport = project.knownImports[objectSym.from]?.[name];
const knownImport = project.resolveKnownImport(objectSym.from, name);
if (knownImport !== undefined) {
return E.right({ type: 'codec', schema: knownImport });
}
Expand Down
7 changes: 6 additions & 1 deletion packages/openapi-generator/src/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { parseSource, type SourceFile } from './sourceFile';
const readFile = promisify(fs.readFile);

export class Project {
readonly knownImports: Record<string, Record<string, KnownCodec>>;
private readonly knownImports: Record<string, Record<string, KnownCodec>>;

private files: Record<string, SourceFile>;

Expand Down Expand Up @@ -90,4 +90,9 @@ export class Project {
}
}
}

resolveKnownImport(path: string, name: string): KnownCodec | undefined {
const baseKey = path.startsWith('.') ? '.' : path;
return this.knownImports[baseKey]?.[name];
}
}
95 changes: 95 additions & 0 deletions packages/openapi-generator/test/project.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import * as E from 'fp-ts/lib/Either';
import assert from 'node:assert';
import test from 'node:test';

import { TestProject } from './testProject';
import { parsePlainInitializer, type Schema } from '../src';
import { KNOWN_IMPORTS, type KnownImports } from '../src/knownImports';

async function testCase(
description: string,
src: string,
knownImports: KnownImports,
expected: Record<string, Schema>,
expectedErrors: string[] = [],
) {
test(description, async () => {
const project = new TestProject(
{ '/index.ts': src },
{ ...KNOWN_IMPORTS, ...knownImports },
);
await project.parseEntryPoint('/index.ts');
const sourceFile = project.get('/index.ts');
if (sourceFile === undefined) {
throw new Error('Source file not found');
}

const actual: Record<string, Schema> = {};
const errors: string[] = [];
for (const symbol of sourceFile.symbols.declarations) {
if (symbol.init !== undefined) {
const result = parsePlainInitializer(project, sourceFile, symbol.init);
if (E.isLeft(result)) {
errors.push(result.left);
} else {
if (symbol.comment !== undefined) {
result.right.comment = symbol.comment;
}
actual[symbol.name] = result.right;
}
}
}

assert.deepStrictEqual(errors, expectedErrors);
assert.deepStrictEqual(actual, expected);
});
}

const EXTERNAL_CUSTOM_CODEC: KnownImports = {
foo: {
bar: () => E.right({ type: 'primitive', value: 'string' }),
},
};

const EXTERNAL_CUSTOM_CODEC_SRC = `
import * as f from 'foo';

export const FOO = f.bar;
`;

testCase(
'External custom codecs are parsed',
EXTERNAL_CUSTOM_CODEC_SRC,
EXTERNAL_CUSTOM_CODEC,
{
FOO: { type: 'primitive', value: 'string' },
},
);

const INTERNAL_CODEC_OVERRIDE: KnownImports = {
'.': {
bar: () => E.right({ type: 'primitive', value: 'string' }),
},
};

const INTERNAL_CODEC_OVERRIDE_SRC = `
import * as t from 'io-ts';
import { bar } from './bar';

export const FOO = t.type({ bar: bar });
`;

testCase(
'Internal codec overrides are parsed',
INTERNAL_CODEC_OVERRIDE_SRC,
INTERNAL_CODEC_OVERRIDE,
{
FOO: {
type: 'object',
properties: {
bar: { type: 'primitive', value: 'string' },
},
required: ['bar'],
},
},
);
5 changes: 3 additions & 2 deletions packages/openapi-generator/test/testProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import resolve from 'resolve';
import { promisify } from 'util';

import { Project } from '../src';
import type { KnownImports } from '../src/knownImports';

export class TestProject extends Project {
private volume: ReturnType<(typeof Volume)['fromJSON']>;

constructor(files: NestedDirectoryJSON) {
super();
constructor(files: NestedDirectoryJSON, knownImports?: KnownImports) {
super({}, knownImports);
this.volume = Volume.fromNestedJSON(files, '/');
}

Expand Down