Skip to content

Commit

Permalink
Add support for parsing template strings
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
bitgopatmcl committed Nov 6, 2024
1 parent dd2c671 commit 0f89046
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 0 deletions.
61 changes: 61 additions & 0 deletions packages/openapi-generator/src/codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,65 @@ 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, Schema>[] = template.expressions.map((expr) =>
parsePlainInitializer(project, source, expr),
);

return pipe(
expressions,
E.sequenceArray,
E.flatMap((schemas) => {
const literals: string[] = [];
for (const schema of schemas) {
if (
schema.type === 'string' &&
schema.enum !== undefined &&
schema.enum.length === 1
) {
literals.push(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');
}
literals.push(String(schemaE.right.enum[0]));
}
}

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 +407,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 @@ -870,3 +870,42 @@ testCase('computed property is parsed', COMPUTED_PROPERTY, {
enum: ['foo'],
}
});

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 0f89046

Please sign in to comment.