UNPKG

27.3 kBJavaScriptView Raw
1'use strict';
2
3function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
4
5const thriftParser = require('@creditkarma/thrift-parser');
6const utils = require('@graphql-mesh/utils');
7const AggregateError = _interopDefault(require('@ardatan/aggregate-error'));
8const graphql = require('graphql');
9const graphqlScalars = require('graphql-scalars');
10const thriftClient = require('@creditkarma/thrift-client');
11const thriftServerCore = require('@creditkarma/thrift-server-core');
12
13/*! *****************************************************************************
14Copyright (c) Microsoft Corporation.
15
16Permission to use, copy, modify, and/or distribute this software for any
17purpose with or without fee is hereby granted.
18
19THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
20REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
21AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
22INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
23LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
24OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
25PERFORMANCE OF THIS SOFTWARE.
26***************************************************************************** */
27
28var __assign = function() {
29 __assign = Object.assign || function __assign(t) {
30 for (var s, i = 1, n = arguments.length; i < n; i++) {
31 s = arguments[i];
32 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
33 }
34 return t;
35 };
36 return __assign.apply(this, arguments);
37};
38
39/**
40 * Source: ftp://ftp.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt
41 */
42/**
43 * Lower case as a function.
44 */
45function lowerCase(str) {
46 return str.toLowerCase();
47}
48
49// Support camel case ("camelCase" -> "camel Case" and "CAMELCase" -> "CAMEL Case").
50var DEFAULT_SPLIT_REGEXP = [/([a-z0-9])([A-Z])/g, /([A-Z])([A-Z][a-z])/g];
51// Remove all non-word characters.
52var DEFAULT_STRIP_REGEXP = /[^A-Z0-9]+/gi;
53/**
54 * Normalize the string into something other libraries can manipulate easier.
55 */
56function noCase(input, options) {
57 if (options === void 0) { options = {}; }
58 var _a = options.splitRegexp, splitRegexp = _a === void 0 ? DEFAULT_SPLIT_REGEXP : _a, _b = options.stripRegexp, stripRegexp = _b === void 0 ? DEFAULT_STRIP_REGEXP : _b, _c = options.transform, transform = _c === void 0 ? lowerCase : _c, _d = options.delimiter, delimiter = _d === void 0 ? " " : _d;
59 var result = replace(replace(input, splitRegexp, "$1\0$2"), stripRegexp, "\0");
60 var start = 0;
61 var end = result.length;
62 // Trim the delimiter from around the output string.
63 while (result.charAt(start) === "\0")
64 start++;
65 while (result.charAt(end - 1) === "\0")
66 end--;
67 // Transform each token independently.
68 return result.slice(start, end).split("\0").map(transform).join(delimiter);
69}
70/**
71 * Replace `re` in the input string with the replacement value.
72 */
73function replace(input, re, value) {
74 if (re instanceof RegExp)
75 return input.replace(re, value);
76 return re.reduce(function (input, re) { return input.replace(re, value); }, input);
77}
78
79function pascalCaseTransform(input, index) {
80 var firstChar = input.charAt(0);
81 var lowerChars = input.substr(1).toLowerCase();
82 if (index > 0 && firstChar >= "0" && firstChar <= "9") {
83 return "_" + firstChar + lowerChars;
84 }
85 return "" + firstChar.toUpperCase() + lowerChars;
86}
87function pascalCase(input, options) {
88 if (options === void 0) { options = {}; }
89 return noCase(input, __assign({ delimiter: "", transform: pascalCaseTransform }, options));
90}
91
92class ThriftHandler {
93 constructor({ config, cache }) {
94 this.config = config;
95 this.cache = cache;
96 }
97 async getMeshSource() {
98 var _a, _b;
99 const { schemaHeaders, serviceName, operationHeaders } = this.config;
100 const rawThrift = await utils.readFileOrUrlWithCache(this.config.idl, this.cache, {
101 allowUnknownExtensions: true,
102 headers: schemaHeaders,
103 });
104 const thriftAST = thriftParser.parse(rawThrift, { organize: false });
105 const enumTypeMap = new Map();
106 const outputTypeMap = new Map();
107 const inputTypeMap = new Map();
108 const rootFields = {};
109 const annotations = {};
110 const methodAnnotations = {};
111 const methodNames = [];
112 const methodParameters = {};
113 const topTypeMap = {};
114 class MeshThriftClient extends thriftServerCore.ThriftClient {
115 constructor() {
116 super(...arguments);
117 this._serviceName = serviceName;
118 this._annotations = annotations;
119 this._methodAnnotations = methodAnnotations;
120 this._methodNames = methodNames;
121 this._methodParameters = methodParameters;
122 }
123 writeType(typeVal, value, output) {
124 switch (typeVal.type) {
125 case thriftServerCore.TType.BOOL:
126 output.writeBool(value);
127 break;
128 case thriftServerCore.TType.BYTE:
129 output.writeByte(value);
130 break;
131 case thriftServerCore.TType.DOUBLE:
132 output.writeDouble(value);
133 break;
134 case thriftServerCore.TType.I16:
135 output.writeI16(value);
136 break;
137 case thriftServerCore.TType.I32:
138 output.writeI32(value);
139 break;
140 case thriftServerCore.TType.I64:
141 output.writeI64(value.toString());
142 break;
143 case thriftServerCore.TType.STRING:
144 output.writeString(value);
145 break;
146 case thriftServerCore.TType.STRUCT: {
147 output.writeStructBegin(typeVal.name);
148 const typeMap = typeVal.fields;
149 for (const argName in value) {
150 const argType = typeMap[argName];
151 const argVal = value[argName];
152 if (argType) {
153 output.writeFieldBegin(argName, argType.type, argType.id);
154 this.writeType(argType, argVal, output);
155 output.writeFieldEnd();
156 }
157 }
158 output.writeFieldStop();
159 output.writeStructEnd();
160 break;
161 }
162 case thriftServerCore.TType.ENUM:
163 // TODO: A
164 break;
165 case thriftServerCore.TType.MAP: {
166 const keys = Object.keys(value);
167 output.writeMapBegin(typeVal.keyType.type, typeVal.valType.type, keys.length);
168 for (const key of keys) {
169 this.writeType(typeVal.keyType, key, output);
170 const val = value[key];
171 this.writeType(typeVal.valType, val, output);
172 }
173 output.writeMapEnd();
174 break;
175 }
176 case thriftServerCore.TType.LIST:
177 output.writeListBegin(typeVal.elementType.type, value.length);
178 for (const element of value) {
179 this.writeType(typeVal.elementType, element, output);
180 }
181 output.writeListEnd();
182 break;
183 case thriftServerCore.TType.SET:
184 output.writeSetBegin(typeVal.elementType.type, value.length);
185 for (const element of value) {
186 this.writeType(typeVal.elementType, element, output);
187 }
188 output.writeSetEnd();
189 break;
190 }
191 }
192 readType(type, input) {
193 switch (type) {
194 case thriftServerCore.TType.BOOL:
195 return input.readBool();
196 case thriftServerCore.TType.BYTE:
197 return input.readByte();
198 case thriftServerCore.TType.DOUBLE:
199 return input.readDouble();
200 case thriftServerCore.TType.I16:
201 return input.readI16();
202 case thriftServerCore.TType.I32:
203 return input.readI32();
204 case thriftServerCore.TType.I64:
205 return BigInt(input.readI64().toString());
206 case thriftServerCore.TType.STRING:
207 return input.readString();
208 case thriftServerCore.TType.STRUCT: {
209 const result = {};
210 input.readStructBegin();
211 while (true) {
212 const field = input.readFieldBegin();
213 const fieldType = field.fieldType;
214 const fieldName = field.fieldName || 'success';
215 if (fieldType === thriftServerCore.TType.STOP) {
216 break;
217 }
218 result[fieldName] = this.readType(fieldType, input);
219 input.readFieldEnd();
220 }
221 input.readStructEnd();
222 return result;
223 }
224 case thriftServerCore.TType.ENUM:
225 // TODO: A
226 break;
227 case thriftServerCore.TType.MAP: {
228 const result = {};
229 const map = input.readMapBegin();
230 for (let i = 0; i < map.size; i++) {
231 const key = this.readType(map.keyType, input);
232 const value = this.readType(map.valueType, input);
233 result[key] = value;
234 }
235 input.readMapEnd();
236 return result;
237 }
238 case thriftServerCore.TType.LIST: {
239 const result = [];
240 const list = input.readListBegin();
241 for (let i = 0; i < list.size; i++) {
242 const element = this.readType(list.elementType, input);
243 result.push(element);
244 }
245 input.readListEnd();
246 return result;
247 }
248 case thriftServerCore.TType.SET: {
249 const result = [];
250 const list = input.readSetBegin();
251 for (let i = 0; i < list.size; i++) {
252 const element = this.readType(list.elementType, input);
253 result.push(element);
254 }
255 input.readSetEnd();
256 return result;
257 }
258 }
259 }
260 async doRequest(methodName, args, fields, context) {
261 const Transport = this.transport;
262 const Protocol = this.protocol;
263 const writer = new Transport();
264 const output = new Protocol(writer);
265 const id = this.incrementRequestId();
266 output.writeMessageBegin(methodName, thriftServerCore.MessageType.CALL, id);
267 this.writeType({
268 name: pascalCase(methodName) + '__Args',
269 type: thriftServerCore.TType.STRUCT,
270 fields,
271 id,
272 }, args, output);
273 output.writeMessageEnd();
274 const data = await this.connection.send(writer.flush(), context);
275 const reader = this.transport.receiver(data);
276 const input = new Protocol(reader);
277 const { fieldName, messageType } = input.readMessageBegin();
278 if (fieldName === methodName) {
279 if (messageType === thriftServerCore.MessageType.EXCEPTION) {
280 const err = thriftServerCore.TApplicationExceptionCodec.decode(input);
281 input.readMessageEnd();
282 return Promise.reject(err);
283 }
284 else {
285 const result = this.readType(thriftServerCore.TType.STRUCT, input);
286 input.readMessageEnd();
287 if (result.success != null) {
288 return result.success;
289 }
290 else {
291 throw new thriftServerCore.TApplicationException(thriftServerCore.TApplicationExceptionType.UNKNOWN, methodName + ' failed: unknown result');
292 }
293 }
294 }
295 else {
296 throw new thriftServerCore.TApplicationException(thriftServerCore.TApplicationExceptionType.WRONG_METHOD_NAME, 'Received a response to an unknown RPC function: ' + fieldName);
297 }
298 }
299 }
300 MeshThriftClient.serviceName = serviceName;
301 MeshThriftClient.annotations = annotations;
302 MeshThriftClient.methodAnnotations = methodAnnotations;
303 MeshThriftClient.methodNames = methodNames;
304 const thriftHttpClient = thriftClient.createHttpClient(MeshThriftClient, {
305 ...this.config,
306 requestOptions: {
307 headers: operationHeaders,
308 },
309 });
310 function processComments(comments) {
311 return comments.map(comment => comment.value).join('\n');
312 }
313 function getGraphQLFunctionType(functionType, id = Math.random()) {
314 let inputType;
315 let outputType;
316 let typeVal;
317 switch (functionType.type) {
318 case thriftParser.SyntaxType.BinaryKeyword:
319 case thriftParser.SyntaxType.StringKeyword:
320 inputType = graphql.GraphQLString;
321 outputType = graphql.GraphQLString;
322 break;
323 case thriftParser.SyntaxType.DoubleKeyword:
324 inputType = graphql.GraphQLFloat;
325 outputType = graphql.GraphQLFloat;
326 typeVal = typeVal || { type: thriftServerCore.TType.DOUBLE };
327 break;
328 case thriftParser.SyntaxType.VoidKeyword:
329 typeVal = typeVal || { type: thriftServerCore.TType.VOID };
330 inputType = graphqlScalars.GraphQLVoid;
331 outputType = graphqlScalars.GraphQLVoid;
332 break;
333 case thriftParser.SyntaxType.BoolKeyword:
334 typeVal = typeVal || { type: thriftServerCore.TType.BOOL };
335 inputType = graphql.GraphQLBoolean;
336 outputType = graphql.GraphQLBoolean;
337 break;
338 case thriftParser.SyntaxType.I8Keyword:
339 inputType = graphql.GraphQLInt;
340 outputType = graphql.GraphQLInt;
341 typeVal = typeVal || { type: thriftServerCore.TType.I08 };
342 break;
343 case thriftParser.SyntaxType.I16Keyword:
344 inputType = graphql.GraphQLInt;
345 outputType = graphql.GraphQLInt;
346 typeVal = typeVal || { type: thriftServerCore.TType.I16 };
347 break;
348 case thriftParser.SyntaxType.I32Keyword:
349 inputType = graphql.GraphQLInt;
350 outputType = graphql.GraphQLInt;
351 typeVal = typeVal || { type: thriftServerCore.TType.I32 };
352 break;
353 case thriftParser.SyntaxType.ByteKeyword:
354 inputType = graphqlScalars.GraphQLByte;
355 outputType = graphqlScalars.GraphQLByte;
356 typeVal = typeVal || { type: thriftServerCore.TType.BYTE };
357 break;
358 case thriftParser.SyntaxType.I64Keyword:
359 inputType = graphqlScalars.GraphQLBigInt;
360 outputType = graphqlScalars.GraphQLBigInt;
361 typeVal = typeVal || { type: thriftServerCore.TType.I64 };
362 break;
363 case thriftParser.SyntaxType.ListType: {
364 const ofTypeList = getGraphQLFunctionType(functionType.valueType, id);
365 inputType = new graphql.GraphQLList(ofTypeList.inputType);
366 outputType = new graphql.GraphQLList(ofTypeList.outputType);
367 typeVal = typeVal || { type: thriftServerCore.TType.LIST, elementType: ofTypeList.typeVal };
368 break;
369 }
370 case thriftParser.SyntaxType.SetType: {
371 const ofSetType = getGraphQLFunctionType(functionType.valueType, id);
372 inputType = new graphql.GraphQLList(ofSetType.inputType);
373 outputType = new graphql.GraphQLList(ofSetType.outputType);
374 typeVal = typeVal || { type: thriftServerCore.TType.SET, elementType: ofSetType.typeVal };
375 break;
376 }
377 case thriftParser.SyntaxType.MapType: {
378 inputType = graphqlScalars.GraphQLJSON;
379 outputType = graphqlScalars.GraphQLJSON;
380 const ofTypeKey = getGraphQLFunctionType(functionType.keyType, id);
381 const ofTypeValue = getGraphQLFunctionType(functionType.valueType, id);
382 typeVal = typeVal || { type: thriftServerCore.TType.MAP, keyType: ofTypeKey.typeVal, valType: ofTypeValue.typeVal };
383 break;
384 }
385 case thriftParser.SyntaxType.Identifier: {
386 const typeName = functionType.value;
387 if (enumTypeMap.has(typeName)) {
388 const enumType = enumTypeMap.get(typeName);
389 inputType = enumType;
390 outputType = enumType;
391 }
392 if (inputTypeMap.has(typeName)) {
393 inputType = inputTypeMap.get(typeName);
394 }
395 if (outputTypeMap.has(typeName)) {
396 outputType = outputTypeMap.get(typeName);
397 }
398 typeVal = topTypeMap[typeName];
399 break;
400 }
401 default:
402 throw new Error(`Unknown function type: ${JSON.stringify(functionType, null, 2)}!`);
403 }
404 return {
405 inputType: inputType,
406 outputType: outputType,
407 typeVal: {
408 ...typeVal,
409 id,
410 },
411 };
412 }
413 const { args: commonArgs, contextVariables } = utils.parseInterpolationStrings(Object.values(operationHeaders || {}));
414 const headersFactory = utils.getInterpolatedHeadersFactory(operationHeaders);
415 switch (thriftAST.type) {
416 case thriftParser.SyntaxType.ThriftDocument: {
417 for (const statement of thriftAST.body) {
418 switch (statement.type) {
419 case thriftParser.SyntaxType.EnumDefinition:
420 enumTypeMap.set(statement.name.value, new graphql.GraphQLEnumType({
421 name: statement.name.value,
422 description: processComments(statement.comments),
423 values: statement.members.reduce((prev, curr) => ({
424 ...prev,
425 [curr.name.value]: {
426 description: processComments(curr.comments),
427 value: curr.name.value,
428 },
429 }), {}),
430 }));
431 break;
432 case thriftParser.SyntaxType.StructDefinition: {
433 const structName = statement.name.value;
434 const description = processComments(statement.comments);
435 const objectFields = {};
436 const inputObjectFields = {};
437 const structTypeVal = {
438 id: Math.random(),
439 name: structName,
440 type: thriftServerCore.TType.STRUCT,
441 fields: {},
442 };
443 topTypeMap[structName] = structTypeVal;
444 const structFieldTypeMap = structTypeVal.fields;
445 for (const field of statement.fields) {
446 const fieldName = field.name.value;
447 let fieldOutputType;
448 let fieldInputType;
449 const description = processComments(field.comments);
450 const processedFieldTypes = getGraphQLFunctionType(field.fieldType, (_a = field.fieldID) === null || _a === void 0 ? void 0 : _a.value);
451 fieldOutputType = processedFieldTypes.outputType;
452 fieldInputType = processedFieldTypes.inputType;
453 if (field.requiredness === 'required') {
454 fieldOutputType = new graphql.GraphQLNonNull(fieldOutputType);
455 fieldInputType = new graphql.GraphQLNonNull(fieldInputType);
456 }
457 objectFields[fieldName] = {
458 type: fieldOutputType,
459 description,
460 };
461 inputObjectFields[fieldName] = {
462 type: fieldInputType,
463 description,
464 };
465 structFieldTypeMap[fieldName] = processedFieldTypes.typeVal;
466 }
467 outputTypeMap.set(structName, new graphql.GraphQLObjectType({
468 name: structName,
469 description,
470 fields: objectFields,
471 }));
472 inputTypeMap.set(structName, new graphql.GraphQLInputObjectType({
473 name: structName + 'Input',
474 description,
475 fields: inputObjectFields,
476 }));
477 break;
478 }
479 case thriftParser.SyntaxType.ServiceDefinition:
480 for (const fnIndex in statement.functions) {
481 const fn = statement.functions[fnIndex];
482 const fnName = fn.name.value;
483 const description = processComments(fn.comments);
484 const { outputType: returnType } = getGraphQLFunctionType(fn.returnType, Number(fnIndex) + 1);
485 const args = {
486 ...commonArgs,
487 };
488 const fieldTypeMap = {};
489 for (const field of fn.fields) {
490 const fieldName = field.name.value;
491 const fieldDescription = processComments(field.comments);
492 let { inputType: fieldType, typeVal } = getGraphQLFunctionType(field.fieldType, (_b = field.fieldID) === null || _b === void 0 ? void 0 : _b.value);
493 if (field.requiredness === 'required') {
494 fieldType = new graphql.GraphQLNonNull(fieldType);
495 }
496 args[fieldName] = {
497 type: fieldType,
498 description: fieldDescription,
499 };
500 fieldTypeMap[fieldName] = typeVal;
501 }
502 rootFields[fnName] = {
503 type: returnType,
504 description,
505 args,
506 resolve: async (root, args, context, info) => thriftHttpClient.doRequest(fnName, args, fieldTypeMap, {
507 headers: headersFactory({ root, args, context, info }),
508 }),
509 };
510 methodNames.push(fnName);
511 methodAnnotations[fnName] = { annotations: {}, fieldAnnotations: {} };
512 methodParameters[fnName] = fn.fields.length + 1;
513 }
514 break;
515 case thriftParser.SyntaxType.TypedefDefinition: {
516 const { inputType, outputType } = getGraphQLFunctionType(statement.definitionType, Math.random());
517 const typeName = statement.name.value;
518 inputTypeMap.set(typeName, inputType);
519 outputTypeMap.set(typeName, outputType);
520 break;
521 }
522 }
523 }
524 const queryObjectType = new graphql.GraphQLObjectType({
525 name: 'Query',
526 fields: rootFields,
527 });
528 const schema = new graphql.GraphQLSchema({
529 query: queryObjectType,
530 });
531 return {
532 schema,
533 contextVariables,
534 };
535 }
536 // break;
537 case thriftParser.SyntaxType.ThriftErrors:
538 throw new AggregateError(thriftAST.errors);
539 }
540 }
541}
542
543module.exports = ThriftHandler;
544//# sourceMappingURL=index.cjs.js.map