diff --git a/packages/openapi-generator/src/codec.ts b/packages/openapi-generator/src/codec.ts index de5b12ae..79e39dda 100644 --- a/packages/openapi-generator/src/codec.ts +++ b/packages/openapi-generator/src/codec.ts @@ -223,7 +223,8 @@ function parseObjectExpression( } else if ( property.key.type !== 'Identifier' && property.key.type !== 'StringLiteral' && - property.key.type !== 'NumericLiteral' + property.key.type !== 'NumericLiteral' && + property.key.type !== 'Computed' ) { return errorLeft(`Unimplemented property key type ${property.key.type}`); } @@ -235,7 +236,41 @@ function parseObjectExpression( commentEndIdx, ); commentStartIdx = (property.value as swc.HasSpan).span.end; - const name = property.key.value; + + let name: string = ''; + if (property.key.type === 'Computed') { + if (property.key.expression.type !== 'Identifier') { + return errorLeft( + `Unimplemented computed property value type ${property.value.type}`, + ); + } + + const initE = findSymbolInitializer( + project, + source, + property.key.expression.value, + ); + if (E.isLeft(initE)) { + return initE; + } + const [newSourceFile, init] = initE.right; + const valueE = parsePlainInitializer(project, newSourceFile, init); + if (E.isLeft(valueE)) { + return valueE; + } + const schema = valueE.right; + if ( + (schema.type === 'string' || schema.type === 'number') && + schema.enum !== undefined + ) { + name = String(schema.enum[0]); + } else { + return errorLeft('Computed property must be string or number literal'); + } + } else { + name = String(property.key.value); + } + const valueE = parsePlainInitializer(project, source, property.value); if (E.isLeft(valueE)) { return valueE; diff --git a/packages/openapi-generator/test/codec.test.ts b/packages/openapi-generator/test/codec.test.ts index 8f2c22e2..6955c7d3 100644 --- a/packages/openapi-generator/test/codec.test.ts +++ b/packages/openapi-generator/test/codec.test.ts @@ -554,7 +554,7 @@ testCase( DECLARATION_COMMENT_WITHOUT_LINE_BREAK, { FOO: { - type: 'number', + type: 'number', primitive: true, comment: { description: 'Test codec', @@ -682,7 +682,7 @@ testCase('second property comment is parsed', SECOND_PROPERTY_COMMENT, { properties: { foo: { type: 'number', primitive: true }, bar: { - type: 'string', + type: 'string', primitive: true, comment: { description: 'this is a comment', @@ -848,3 +848,25 @@ testCase('object assign is parsed', OBJECT_ASSIGN, { required: ['foo', 'bar'], }, }); + +const COMPUTED_PROPERTY = ` +import * as t from 'io-ts'; +const key = 'foo'; +export const FOO = t.type({ + [key]: t.number, +}); +`; + +testCase('computed property is parsed', COMPUTED_PROPERTY, { + FOO: { + type: 'object', + properties: { + foo: { type: 'number', primitive: true }, + }, + required: ['foo'], + }, + key: { + type: 'string', + enum: ['foo'], + } +});