Skip to content

Commit

Permalink
Merge pull request #944 from BitGo/bitgopatmcl/template-string-parsing
Browse files Browse the repository at this point in the history
Add support for parsing template strings
  • Loading branch information
ericcrosson-bitgo authored Nov 11, 2024
2 parents 1795aed + 982e60c commit 8c9dd57
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 0 deletions.
66 changes: 66 additions & 0 deletions packages/openapi-generator/src/codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,70 @@ function parseArrayExpression(
return E.right({ type: 'tuple', schemas: result });
}

function parseTemplateLiteral(
project: Project,
source: SourceFile,
template: swc.TemplateLiteral,
): E.Either<string, Schema> {
const expressions: E.Either<string, string>[] = template.expressions.map((expr) => {
const schemaE = parsePlainInitializer(project, source, expr);
if (E.isLeft(schemaE)) {
return schemaE;
}
const schema = schemaE.right;
if (
schema.type === 'string' &&
schema.enum !== undefined &&
schema.enum.length === 1
) {
return E.right(String(schema.enum[0]));
} else if (schema.type === 'ref') {
const realInitE = findSymbolInitializer(project, source, schema.name);
if (E.isLeft(realInitE)) {
return realInitE;
}
const schemaE = parsePlainInitializer(
project,
realInitE.right[0],
realInitE.right[1],
);
if (E.isLeft(schemaE)) {
return schemaE;
}
if (schemaE.right.type !== 'string' || schemaE.right.enum === undefined) {
return errorLeft('Template element must be string literal');
}
return E.right(String(schemaE.right.enum[0]));
} else {
return errorLeft('Template element must be string literal');
}
});

return pipe(
expressions,
E.sequenceArray,
E.flatMap((literals) => {
const quasis = template.quasis.map((quasi) => quasi.cooked);
const result = quasis.reduce(
(acc, quasi, index) => {
if (index < literals.length) {
acc.push(quasi ?? '', literals[index]!);
} else {
acc.push(quasi ?? '');
}
return acc;
},
[] as (string | Schema)[],
);

return E.right({
type: 'string',
enum: [result.join('')],
});
}),
);
}

export function parsePlainInitializer(
project: Project,
source: SourceFile,
Expand All @@ -348,6 +412,8 @@ export function parsePlainInitializer(
return E.right({ type: 'undefined' });
} else if (init.type === 'TsConstAssertion' || init.type === 'TsAsExpression') {
return parsePlainInitializer(project, source, init.expression);
} else if (init.type === 'TemplateLiteral') {
return parseTemplateLiteral(project, source, init);
} else if (
init.type === 'Identifier' ||
init.type === 'MemberExpression' ||
Expand Down
39 changes: 39 additions & 0 deletions packages/openapi-generator/test/codec.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -882,3 +882,42 @@ testCase('computed property is parsed', COMPUTED_PROPERTY, {
required: ['bar'],
},
});

const TEMPLATE_LITERAL = `
import * as t from 'io-ts';
const test = 'foo';
export const FOO = \`\${test}bar\`;
`;

testCase('basic template literal is parsed', TEMPLATE_LITERAL, {
FOO: {
type: 'string',
enum: ['foobar'],
},
test: {
type: 'string',
enum: ['foo'],
},
});

const MULTI_TEMPLATE_LITERAL = `
import * as t from 'io-ts';
const test = 'foo';
const test2 = 'baz';
export const FOO = \`aaa\${test}bar\${test2}bat\`;
`;

testCase('compound template literal is parsed', MULTI_TEMPLATE_LITERAL, {
FOO: {
type: 'string',
enum: ['aaafoobarbazbat'],
},
test: {
type: 'string',
enum: ['foo'],
},
test2: {
type: 'string',
enum: ['baz'],
},
});

0 comments on commit 8c9dd57

Please sign in to comment.