Skip to content

Commit 982e60c

Browse files
committed
feat: add support for parsing template strings
Adds support for parsing basic template strings in `packages/openapi-generator`. * **Add template string parsing function** - Add `parseTemplateLiteral` function to handle template strings in `packages/openapi-generator/src/codec.ts`. - Update `parsePlainInitializer` to call `parseTemplateLiteral` when encountering a template literal. * **Add tests for template string parsing** - Add test cases for basic and compound template literals in `packages/openapi-generator/test/codec.test.ts`.
1 parent 9d426e4 commit 982e60c

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed

packages/openapi-generator/src/codec.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,70 @@ function parseArrayExpression(
327327
return E.right({ type: 'tuple', schemas: result });
328328
}
329329

330+
function parseTemplateLiteral(
331+
project: Project,
332+
source: SourceFile,
333+
template: swc.TemplateLiteral,
334+
): E.Either<string, Schema> {
335+
const expressions: E.Either<string, string>[] = template.expressions.map((expr) => {
336+
const schemaE = parsePlainInitializer(project, source, expr);
337+
if (E.isLeft(schemaE)) {
338+
return schemaE;
339+
}
340+
const schema = schemaE.right;
341+
if (
342+
schema.type === 'string' &&
343+
schema.enum !== undefined &&
344+
schema.enum.length === 1
345+
) {
346+
return E.right(String(schema.enum[0]));
347+
} else if (schema.type === 'ref') {
348+
const realInitE = findSymbolInitializer(project, source, schema.name);
349+
if (E.isLeft(realInitE)) {
350+
return realInitE;
351+
}
352+
const schemaE = parsePlainInitializer(
353+
project,
354+
realInitE.right[0],
355+
realInitE.right[1],
356+
);
357+
if (E.isLeft(schemaE)) {
358+
return schemaE;
359+
}
360+
if (schemaE.right.type !== 'string' || schemaE.right.enum === undefined) {
361+
return errorLeft('Template element must be string literal');
362+
}
363+
return E.right(String(schemaE.right.enum[0]));
364+
} else {
365+
return errorLeft('Template element must be string literal');
366+
}
367+
});
368+
369+
return pipe(
370+
expressions,
371+
E.sequenceArray,
372+
E.flatMap((literals) => {
373+
const quasis = template.quasis.map((quasi) => quasi.cooked);
374+
const result = quasis.reduce(
375+
(acc, quasi, index) => {
376+
if (index < literals.length) {
377+
acc.push(quasi ?? '', literals[index]!);
378+
} else {
379+
acc.push(quasi ?? '');
380+
}
381+
return acc;
382+
},
383+
[] as (string | Schema)[],
384+
);
385+
386+
return E.right({
387+
type: 'string',
388+
enum: [result.join('')],
389+
});
390+
}),
391+
);
392+
}
393+
330394
export function parsePlainInitializer(
331395
project: Project,
332396
source: SourceFile,
@@ -348,6 +412,8 @@ export function parsePlainInitializer(
348412
return E.right({ type: 'undefined' });
349413
} else if (init.type === 'TsConstAssertion' || init.type === 'TsAsExpression') {
350414
return parsePlainInitializer(project, source, init.expression);
415+
} else if (init.type === 'TemplateLiteral') {
416+
return parseTemplateLiteral(project, source, init);
351417
} else if (
352418
init.type === 'Identifier' ||
353419
init.type === 'MemberExpression' ||

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,3 +870,42 @@ testCase('computed property is parsed', COMPUTED_PROPERTY, {
870870
enum: ['foo'],
871871
}
872872
});
873+
874+
const TEMPLATE_LITERAL = `
875+
import * as t from 'io-ts';
876+
const test = 'foo';
877+
export const FOO = \`\${test}bar\`;
878+
`;
879+
880+
testCase('basic template literal is parsed', TEMPLATE_LITERAL, {
881+
FOO: {
882+
type: 'string',
883+
enum: ['foobar'],
884+
},
885+
test: {
886+
type: 'string',
887+
enum: ['foo'],
888+
},
889+
});
890+
891+
const MULTI_TEMPLATE_LITERAL = `
892+
import * as t from 'io-ts';
893+
const test = 'foo';
894+
const test2 = 'baz';
895+
export const FOO = \`aaa\${test}bar\${test2}bat\`;
896+
`;
897+
898+
testCase('compound template literal is parsed', MULTI_TEMPLATE_LITERAL, {
899+
FOO: {
900+
type: 'string',
901+
enum: ['aaafoobarbazbat'],
902+
},
903+
test: {
904+
type: 'string',
905+
enum: ['foo'],
906+
},
907+
test2: {
908+
type: 'string',
909+
enum: ['baz'],
910+
},
911+
});

0 commit comments

Comments
 (0)