@travetto/runtime
Version:
Runtime for travetto applications.
87 lines (74 loc) • 2.69 kB
text/typescript
import ts from 'typescript';
import { TransformerState, OnInterface, OnCall, OnTypeAlias } from '@travetto/transformer';
import { MetadataRegistrationUtil } from './transformer/metadata.ts';
const SRC = '@travetto/runtime/src/types.ts';
/**
* Providing support for concrete types
*/
export class ConcreteTransformer {
static #isConcreteSimple(node: ts.InterfaceDeclaration | ts.TypeAliasDeclaration): boolean {
return /^\s*[*]\s+@concrete\s*$/gm.test(node.getFullText());
}
static #createConcreteFunction(state: TransformerState, name: string | ts.Identifier): ts.FunctionDeclaration {
const final = typeof name === 'string' ? name : name.getText();
const dec = state.factory.createFunctionDeclaration(
// eslint-disable-next-line no-bitwise
state.factory.createModifiersFromModifierFlags(ts.ModifierFlags.Export | ts.ModifierFlags.Const),
undefined, `${final}$Concrete`, [], [], undefined,
state.factory.createBlock([])
);
state.addStatements([
dec,
state.factory.createExpressionStatement(
state.factory.createCallExpression(
state.createAccess('Object', 'defineProperty'),
undefined,
[
dec.name!,
state.fromLiteral('name'),
state.fromLiteral({ value: final })
]
)
)
]);
return dec;
}
/**
* Handle concrete interface
*/
()
static onInterface(state: TransformerState, node: ts.InterfaceDeclaration): typeof node {
if (this.#isConcreteSimple(node)) {
const func = this.#createConcreteFunction(state, node.name);
MetadataRegistrationUtil.registerFunction(state, func, node);
}
return node;
}
/**
* Handle type alias
*/
()
static onTypeAlias(state: TransformerState, node: ts.TypeAliasDeclaration): typeof node {
if (this.#isConcreteSimple(node)) {
const func = this.#createConcreteFunction(state, node.name);
MetadataRegistrationUtil.registerFunction(state, func, node);
}
return node;
}
()
static onToConcreteCall(state: TransformerState, node: ts.CallExpression): typeof node {
if (ts.isIdentifier(node.expression) && node.expression.text === 'toConcrete' && node.typeArguments?.length && node.arguments.length === 0) {
const type = state.resolveType(node.expression);
if ('importName' in type && type.importName === SRC) {
const [target] = node.typeArguments;
return state.factory.updateCallExpression(
node,
node.expression,
node.typeArguments,
[state.getConcreteType(target)]
);
}
}
return node;
}
}