|
1 |
| -import { PropertyName, VariableDeclaration, VariableStatement} from 'typescript'; |
| 1 | +import { PropertyName, VariableDeclaration, VariableStatement } from 'typescript'; |
2 | 2 | import * as ts from 'typescript';
|
| 3 | +import { IsTypescriptType } from '../descriptor/tsLibs/typecriptLibs'; |
| 4 | +import { TypescriptHelper } from '../descriptor/helper/helper'; |
| 5 | +import { NodeToString } from '../printNode'; |
| 6 | + |
| 7 | +export interface MethodSignature extends ts.MethodSignature { |
| 8 | + parameters: ts.NodeArray<ParameterDeclaration>; |
| 9 | + type: ts.TypeNode; |
| 10 | +} |
| 11 | + |
| 12 | +export interface ParameterDeclaration extends ts.ParameterDeclaration { |
| 13 | + type: ts.TypeNode; |
| 14 | +} |
3 | 15 |
|
4 | 16 | export namespace TypescriptCreator {
|
5 | 17 | export function createArrowFunction(block: ts.ConciseBody, parameter: ReadonlyArray<ts.ParameterDeclaration> = []): ts.ArrowFunction {
|
@@ -91,6 +103,131 @@ export namespace TypescriptCreator {
|
91 | 103 | );
|
92 | 104 | }
|
93 | 105 |
|
| 106 | + function serialize(node: ts.TypeNode): string { |
| 107 | + if (TypescriptHelper.IsLiteralOrPrimitive(node) || ts.isTypeReferenceNode(node)) { |
| 108 | + return NodeToString(node); |
| 109 | + } |
| 110 | + |
| 111 | + if (ts.isTypeLiteralNode(node)) { |
| 112 | + const serialized: string = node.members |
| 113 | + .filter((member: ts.TypeElement): member is ts.PropertySignature => ts.isPropertySignature(member)) |
| 114 | + .map((member: ts.PropertySignature) => member.type ? serialize(member.type) : '').join('|'); |
| 115 | + return `{${serialized}}`; |
| 116 | + } |
| 117 | + |
| 118 | + if (ts.isUnionTypeNode(node) || ts.isIntersectionTypeNode(node)) { |
| 119 | + const serialized: string = node.types.map((member: ts.TypeNode) => serialize(member)).join('|'); |
| 120 | + return `[${serialized}]`; |
| 121 | + } |
| 122 | + |
| 123 | + return ''; |
| 124 | + } |
| 125 | + |
| 126 | + // FIXME: This is not really a hash right now. Keep this as is for debugging |
| 127 | + // though... maybe even be more verbose than this. |
| 128 | + export function createSignatureHash(signature: ts.SignatureDeclaration | ts.SignatureDeclaration[]): string { |
| 129 | + function serializeSignature(s: ts.SignatureDeclaration): string { |
| 130 | + const parameters: ts.NodeArray<ts.ParameterDeclaration> = s.parameters; |
| 131 | + |
| 132 | + const signatureParts: string[] = []; |
| 133 | + |
| 134 | + if (parameters.length) { |
| 135 | + signatureParts.push( |
| 136 | + ...parameters.map(<T extends { type?: ts.TypeNode }>(p: T) => { |
| 137 | + const type: ts.TypeNode | undefined = p.type; |
| 138 | + |
| 139 | + if (!type) { |
| 140 | + return ''; |
| 141 | + } |
| 142 | + |
| 143 | + if (ts.isFunctionLike(type)) { |
| 144 | + return `(${serializeSignature(type)})`; |
| 145 | + } |
| 146 | + |
| 147 | + return serialize(type); |
| 148 | + }) |
| 149 | + ); |
| 150 | + } |
| 151 | + |
| 152 | + const signatureType: ts.TypeNode | undefined = s.type; |
| 153 | + |
| 154 | + if (signatureType) { |
| 155 | + signatureParts.push(serialize(signatureType)); |
| 156 | + } |
| 157 | + |
| 158 | + return signatureParts.join('|'); |
| 159 | + } |
| 160 | + |
| 161 | + const signatures: ts.SignatureDeclaration[] = Array.isArray(signature) ? signature : [signature]; |
| 162 | + |
| 163 | + // TODO: Check debug option and emit a verbose string representation |
| 164 | + |
| 165 | + // TODO: Make sure this don't result in collisions |
| 166 | + return Buffer.from( |
| 167 | + [ |
| 168 | + Array.from(signatures.map((s: ts.SignatureDeclaration) => serializeSignature(s)).join('|')) |
| 169 | + .reduce((s: number, c: string) => { |
| 170 | + // eslint-disable-next-line |
| 171 | + const charCode: number = c.charCodeAt(0) | 0; |
| 172 | + |
| 173 | + return Math.imul(31, s) + charCode; |
| 174 | + }, 0), |
| 175 | + ], |
| 176 | + ).toString('base64'); |
| 177 | + } |
| 178 | + |
| 179 | + function isDefinitiveMethodSignature(signature: ts.MethodSignature): signature is MethodSignature { |
| 180 | + return !!signature.type; |
| 181 | + } |
| 182 | + |
| 183 | + function isDefinitiveParameterDeclaration(parameter: ts.ParameterDeclaration): parameter is ParameterDeclaration { |
| 184 | + return !!parameter.type; |
| 185 | + } |
| 186 | + |
| 187 | + export function createMethodSignature(parameterTypes: Array<ts.TypeNode | undefined> = [], returnType: ts.TypeNode | undefined): MethodSignature { |
| 188 | + const parameters: ParameterDeclaration[] = parameterTypes |
| 189 | + .filter((type: ts.TypeNode | undefined): type is ts.TypeNode => !!type) |
| 190 | + .map((parameterType: ts.TypeNode, i: number) => { |
| 191 | + // TODO: Merge/move this block with/to typescriptLibs.ts |
| 192 | + if (ts.isTypeReferenceNode(parameterType)) { |
| 193 | + const declaration: ts.Declaration = TypescriptHelper.GetDeclarationFromNode(parameterType.typeName); |
| 194 | + if (IsTypescriptType(declaration)) { |
| 195 | + parameterType = ts.createFunctionTypeNode(undefined, [], ts.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword)); |
| 196 | + } |
| 197 | + } |
| 198 | + |
| 199 | + const parameter: ts.ParameterDeclaration = ts.createParameter( |
| 200 | + undefined, |
| 201 | + undefined, |
| 202 | + undefined, |
| 203 | + `__${i++}`, |
| 204 | + undefined, |
| 205 | + parameterType, |
| 206 | + undefined, |
| 207 | + ); |
| 208 | + |
| 209 | + if (!isDefinitiveParameterDeclaration(parameter)) { |
| 210 | + throw new Error(); |
| 211 | + } |
| 212 | + |
| 213 | + return parameter; |
| 214 | + }); |
| 215 | + |
| 216 | + const signature: ts.MethodSignature = ts.createMethodSignature( |
| 217 | + undefined, |
| 218 | + parameters, |
| 219 | + returnType || ts.createKeywordTypeNode(ts.SyntaxKind.NullKeyword), |
| 220 | + '', |
| 221 | + undefined, |
| 222 | + ); |
| 223 | + |
| 224 | + if (!isDefinitiveMethodSignature(signature)) { |
| 225 | + throw new Error(); |
| 226 | + } |
| 227 | + |
| 228 | + return signature; |
| 229 | + } |
| 230 | + |
94 | 231 | export function createVariableDeclaration(variableIdentifier: ts.Identifier, initializer: ts.Expression): ts.VariableDeclaration {
|
95 | 232 | return ts.createVariableDeclaration(
|
96 | 233 | variableIdentifier,
|
|
0 commit comments