Skip to content

Commit 455a3f6

Browse files
committed
chore(transformer): Move branching logic to its own file
1 parent d0faca4 commit 455a3f6

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import ts from 'typescript';
2+
import { MethodSignature } from '../../helper/creator';
3+
import { TypescriptHelper } from '../helper/helper';
4+
import { GetDescriptor } from '../descriptor';
5+
import { Scope } from '../../scope/scope';
6+
7+
function CreateTypeEquality(typeVariableMap: Map<ts.TypeNode, ts.StringLiteral | ts.Identifier>, parameterType: ts.TypeNode | undefined, primaryDeclaration: ts.ParameterDeclaration): ts.Expression {
8+
const declarationName: ts.Identifier = TypescriptHelper.ExtractFirstIdentifier(primaryDeclaration.name);
9+
10+
if (!parameterType) {
11+
return ts.createPrefix(
12+
ts.SyntaxKind.ExclamationToken,
13+
ts.createPrefix(
14+
ts.SyntaxKind.ExclamationToken,
15+
declarationName,
16+
),
17+
);
18+
}
19+
20+
if (TypescriptHelper.IsLiteralOrPrimitive(parameterType)) {
21+
return ts.createStrictEquality(
22+
ts.createTypeOf(declarationName),
23+
parameterType ? ts.createStringLiteral(parameterType.getText()) : ts.createVoidZero(),
24+
);
25+
}
26+
27+
if (typeVariableMap.has(parameterType)) {
28+
// eslint-disable-next-line
29+
const parameterIdentifier: ts.StringLiteral | ts.Identifier = typeVariableMap.get(parameterType)!;
30+
return ts.createStrictEquality(
31+
ts.createLogicalAnd(declarationName, ts.createPropertyAccess(declarationName, '__ident')),
32+
parameterIdentifier,
33+
);
34+
}
35+
return ts.createBinary(declarationName, ts.SyntaxKind.InstanceOfKeyword, ts.createIdentifier('Object'));
36+
}
37+
38+
function CreateUnionTypeOfEquality(
39+
typeVariableMap: Map<ts.TypeNode, ts.StringLiteral | ts.Identifier>,
40+
signatureType: ts.TypeNode | undefined,
41+
primaryDeclaration: ts.ParameterDeclaration,
42+
): ts.Expression {
43+
const typeNodesAndVariableReferences: Array<ts.TypeNode> = [];
44+
45+
if (signatureType) {
46+
if (ts.isTypeNode(signatureType) && ts.isUnionTypeNode(signatureType)) {
47+
typeNodesAndVariableReferences.push(...signatureType.types);
48+
} else {
49+
typeNodesAndVariableReferences.push(signatureType);
50+
}
51+
}
52+
53+
const [firstType, ...remainingTypes]: Array<ts.TypeNode> = typeNodesAndVariableReferences;
54+
55+
return remainingTypes.reduce(
56+
(prevStatement: ts.Expression, typeNode: ts.TypeNode) =>
57+
ts.createLogicalOr(
58+
prevStatement,
59+
CreateTypeEquality(typeVariableMap, typeNode, primaryDeclaration),
60+
),
61+
CreateTypeEquality(typeVariableMap, firstType, primaryDeclaration),
62+
);
63+
}
64+
65+
function ResolveParameterBranch(
66+
typeVariableMap: Map<ts.TypeNode, ts.StringLiteral | ts.Identifier>,
67+
declarations: ts.NodeArray<ts.ParameterDeclaration> | [undefined],
68+
longedSignature: MethodSignature,
69+
returnType: ts.TypeNode,
70+
elseBranch: ts.Statement,
71+
scope: Scope,
72+
): ts.Statement {
73+
// NOTE: The strange signature here is to cover an empty list of declarations,
74+
// then firstDeclaration will be undefined.
75+
const [firstDeclaration, ...remainingDeclarations]: ts.NodeArray<ts.ParameterDeclaration> | [undefined] = declarations;
76+
77+
// TODO: These conditions quickly grow in size, but it should be possible to
78+
// squeeze things together and optimize it with something like:
79+
//
80+
// const typeOf = function (left, right) { return typeof left === right; }
81+
// const evaluate = (function(left, right) { return this._ = this._ || typeOf(left, right); }).bind({})
82+
//
83+
// if (evaluate(firstArg, 'boolean') && evaluate(secondArg, 'number') && ...) {
84+
// ...
85+
// }
86+
//
87+
// `this._' acts as a cache, since the control flow may evaluate the same
88+
// conditions multiple times.
89+
const condition: ts.Expression = remainingDeclarations.reduce(
90+
(prevStatement: ts.Expression, declaration: ts.ParameterDeclaration, index: number) =>
91+
ts.createLogicalAnd(
92+
prevStatement,
93+
CreateUnionTypeOfEquality(typeVariableMap, declaration.type, longedSignature.parameters[index + 1]),
94+
),
95+
CreateUnionTypeOfEquality(typeVariableMap, firstDeclaration?.type, longedSignature.parameters[0]),
96+
);
97+
98+
return ts.createIf(condition, ts.createReturn(GetDescriptor(returnType, scope)), elseBranch);
99+
}
100+
101+
export function ResolveSignatureElseBranch(
102+
typeVariableMap: Map<ts.TypeNode, ts.StringLiteral | ts.Identifier>,
103+
signatures: MethodSignature[],
104+
longestParameterList: MethodSignature,
105+
scope: Scope,
106+
): ts.Statement {
107+
const [signature, ...remainingSignatures]: MethodSignature[] = signatures;
108+
109+
const indistinctSignatures: boolean = signatures.every((sig: ts.MethodSignature) => !sig.parameters?.length);
110+
if (!remainingSignatures.length || indistinctSignatures) {
111+
return ts.createReturn(GetDescriptor(signature.type, scope));
112+
}
113+
114+
const elseBranch: ts.Statement = ResolveSignatureElseBranch(typeVariableMap, remainingSignatures, longestParameterList, scope);
115+
116+
const currentParameters: ts.NodeArray<ts.ParameterDeclaration> = signature.parameters || [];
117+
return ResolveParameterBranch(typeVariableMap, currentParameters, longestParameterList, signature.type, elseBranch, scope);
118+
}

0 commit comments

Comments
 (0)