Skip to content

Commit 8c9dd57

Browse files
Merge pull request #944 from BitGo/bitgopatmcl/template-string-parsing
Add support for parsing template strings
2 parents 1795aed + 982e60c commit 8c9dd57

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
@@ -882,3 +882,42 @@ testCase('computed property is parsed', COMPUTED_PROPERTY, {
882882
required: ['bar'],
883883
},
884884
});
885+
886+
const TEMPLATE_LITERAL = `
887+
import * as t from 'io-ts';
888+
const test = 'foo';
889+
export const FOO = \`\${test}bar\`;
890+
`;
891+
892+
testCase('basic template literal is parsed', TEMPLATE_LITERAL, {
893+
FOO: {
894+
type: 'string',
895+
enum: ['foobar'],
896+
},
897+
test: {
898+
type: 'string',
899+
enum: ['foo'],
900+
},
901+
});
902+
903+
const MULTI_TEMPLATE_LITERAL = `
904+
import * as t from 'io-ts';
905+
const test = 'foo';
906+
const test2 = 'baz';
907+
export const FOO = \`aaa\${test}bar\${test2}bat\`;
908+
`;
909+
910+
testCase('compound template literal is parsed', MULTI_TEMPLATE_LITERAL, {
911+
FOO: {
912+
type: 'string',
913+
enum: ['aaafoobarbazbat'],
914+
},
915+
test: {
916+
type: 'string',
917+
enum: ['foo'],
918+
},
919+
test2: {
920+
type: 'string',
921+
enum: ['baz'],
922+
},
923+
});

0 commit comments

Comments
 (0)