@graphql-mesh/soap 1.0.0-alpha-3fc47d119.0 → 1.0.0-alpha-20230420181317-a95037648
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/index.js +56 -0
- package/cjs/package.json +1 -0
- package/esm/index.js +53 -0
- package/package.json +26 -21
- package/typings/index.d.cts +10 -0
- package/typings/index.d.ts +10 -0
- package/index.d.ts +0 -13
- package/index.js +0 -1063
- package/index.mjs +0 -1059
- package/soap-graphql/index.d.ts +0 -4
- package/soap-graphql/node-soap/index.d.ts +0 -3
- package/soap-graphql/node-soap/node-soap-caller.d.ts +0 -18
- package/soap-graphql/node-soap/node-soap-endpoint.d.ts +0 -58
- package/soap-graphql/node-soap/node-soap-resolver.d.ts +0 -26
- package/soap-graphql/node-soap/node-soap.d.ts +0 -21
- package/soap-graphql/soap-graphql.d.ts +0 -62
- package/soap-graphql/soap2graphql/custom-type-resolver.d.ts +0 -64
- package/soap-graphql/soap2graphql/index.d.ts +0 -6
- package/soap-graphql/soap2graphql/name-resolver.d.ts +0 -5
- package/soap-graphql/soap2graphql/schema-resolver.d.ts +0 -30
- package/soap-graphql/soap2graphql/soap-caller.d.ts +0 -17
- package/soap-graphql/soap2graphql/soap-endpoint.d.ts +0 -66
- package/soap-graphql/soap2graphql/soap2graphql.d.ts +0 -83
package/index.mjs
DELETED
|
@@ -1,1059 +0,0 @@
|
|
|
1
|
-
import soap from 'soap';
|
|
2
|
-
import { GraphQLString, GraphQLID, GraphQLList, GraphQLBoolean, GraphQLInt, GraphQLFloat, GraphQLObjectType, GraphQLInterfaceType, GraphQLInputObjectType, GraphQLSchema } from 'graphql';
|
|
3
|
-
import { GraphQLByte, GraphQLHexadecimal, GraphQLDuration, GraphQLURL, GraphQLNonNegativeInt, GraphQLPositiveInt, GraphQLNonPositiveInt, GraphQLNegativeInt, GraphQLBigInt, GraphQLDateTime, GraphQLDate, GraphQLTime, GraphQLJSON } from 'graphql-scalars';
|
|
4
|
-
import { util, process } from '@graphql-mesh/cross-helpers';
|
|
5
|
-
import { loadFromModuleExportExpression, getHeadersObj, readFileOrUrl } from '@graphql-mesh/utils';
|
|
6
|
-
import { PredefinedProxyOptions } from '@graphql-mesh/store';
|
|
7
|
-
|
|
8
|
-
async function createSoapClient(url, options = {}) {
|
|
9
|
-
const opts = !options.options ? {} : options.options;
|
|
10
|
-
return new Promise((resolve, reject) => {
|
|
11
|
-
try {
|
|
12
|
-
soap.createClient(url, opts, (err, client) => {
|
|
13
|
-
if (err) {
|
|
14
|
-
reject(err);
|
|
15
|
-
}
|
|
16
|
-
else {
|
|
17
|
-
if (options.basicAuth) {
|
|
18
|
-
client.setSecurity(new soap.BasicAuthSecurity(options.basicAuth.username, options.basicAuth.password));
|
|
19
|
-
}
|
|
20
|
-
resolve(client);
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
catch (err) {
|
|
25
|
-
reject(err);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const defaultOutputNameResolver = (soapType) => {
|
|
31
|
-
return !soapType ? null : !soapType.name ? null : capitalizeFirstLetter(soapType.name);
|
|
32
|
-
};
|
|
33
|
-
const defaultInputNameResolver = (soapType) => {
|
|
34
|
-
return !soapType ? null : !soapType.name ? null : capitalizeFirstLetter(soapType.name) + 'Input';
|
|
35
|
-
};
|
|
36
|
-
const defaultInterfaceNameResolver = (soapType) => {
|
|
37
|
-
return !soapType ? null : !soapType.name ? null : 'i' + capitalizeFirstLetter(soapType.name);
|
|
38
|
-
};
|
|
39
|
-
function capitalizeFirstLetter(value) {
|
|
40
|
-
return value.charAt(0).toUpperCase() + value.substring(1);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Default implementation of CustomTypeResolver.
|
|
45
|
-
* Based on https://www.w3.org/TR/xmlschema-2/#built-in-datatypes
|
|
46
|
-
*/
|
|
47
|
-
class DefaultTypeResolver {
|
|
48
|
-
constructor() {
|
|
49
|
-
this.string = GraphQLString;
|
|
50
|
-
this.base64Binary = GraphQLByte;
|
|
51
|
-
this.hexBinary = GraphQLHexadecimal;
|
|
52
|
-
this.duration = GraphQLDuration;
|
|
53
|
-
this.gYearMonth = GraphQLString;
|
|
54
|
-
this.gYear = GraphQLString;
|
|
55
|
-
this.gMonthDay = GraphQLString;
|
|
56
|
-
this.gDay = GraphQLString;
|
|
57
|
-
this.gMonth = GraphQLString;
|
|
58
|
-
this.anyURI = GraphQLURL;
|
|
59
|
-
this.QName = GraphQLString;
|
|
60
|
-
this.normalizedString = GraphQLString;
|
|
61
|
-
this.token = GraphQLString;
|
|
62
|
-
this.NMTOKEN = GraphQLString;
|
|
63
|
-
this.NMTOKENS = GraphQLString;
|
|
64
|
-
this.language = GraphQLString;
|
|
65
|
-
this.Name = GraphQLString;
|
|
66
|
-
this.NCName = GraphQLString;
|
|
67
|
-
this.IDREF = GraphQLID;
|
|
68
|
-
this.IDREFS = new GraphQLList(GraphQLID);
|
|
69
|
-
this.ENTITY = GraphQLID;
|
|
70
|
-
this.ENTITIES = new GraphQLList(GraphQLID);
|
|
71
|
-
this.ID = GraphQLID;
|
|
72
|
-
this.boolean = GraphQLBoolean;
|
|
73
|
-
this.byte = GraphQLByte;
|
|
74
|
-
this.unsignedByte = GraphQLByte;
|
|
75
|
-
this.short = GraphQLInt;
|
|
76
|
-
this.unsignedShort = GraphQLNonNegativeInt;
|
|
77
|
-
this.int = GraphQLInt;
|
|
78
|
-
this.unsignedInt = GraphQLNonNegativeInt;
|
|
79
|
-
this.integer = GraphQLInt;
|
|
80
|
-
this.positiveInteger = GraphQLPositiveInt;
|
|
81
|
-
this.nonPositiveInteger = GraphQLNonPositiveInt;
|
|
82
|
-
this.negativeInteger = GraphQLNegativeInt;
|
|
83
|
-
this.nonNegativeInteger = GraphQLNonNegativeInt;
|
|
84
|
-
this.long = GraphQLBigInt;
|
|
85
|
-
this.unsignedLong = GraphQLBigInt;
|
|
86
|
-
this.decimal = GraphQLFloat;
|
|
87
|
-
this.float = GraphQLFloat;
|
|
88
|
-
this.double = GraphQLFloat;
|
|
89
|
-
this.dateTime = GraphQLDateTime;
|
|
90
|
-
this.date = GraphQLDate;
|
|
91
|
-
this.time = GraphQLTime;
|
|
92
|
-
}
|
|
93
|
-
resolve(typeName) {
|
|
94
|
-
return this[typeName];
|
|
95
|
-
}
|
|
96
|
-
outputType(typeName) {
|
|
97
|
-
return this.resolve(typeName);
|
|
98
|
-
}
|
|
99
|
-
inputType(typeName) {
|
|
100
|
-
return this.resolve(typeName);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
class SchemaResolver {
|
|
105
|
-
constructor(soapEndpoint, soapCaller, options, logger) {
|
|
106
|
-
this.soapEndpoint = soapEndpoint;
|
|
107
|
-
this.soapCaller = soapCaller;
|
|
108
|
-
this.logger = logger;
|
|
109
|
-
this.outputResolver = null;
|
|
110
|
-
this.inputResolver = null;
|
|
111
|
-
this.options = this.defaultOptions(options);
|
|
112
|
-
}
|
|
113
|
-
defaultOptions(options) {
|
|
114
|
-
options = !options ? {} : Object.assign({}, options);
|
|
115
|
-
if (!options.outputNameResolver) {
|
|
116
|
-
options.outputNameResolver = defaultOutputNameResolver;
|
|
117
|
-
}
|
|
118
|
-
if (!options.interfaceNameResolver) {
|
|
119
|
-
options.interfaceNameResolver = defaultInterfaceNameResolver;
|
|
120
|
-
}
|
|
121
|
-
if (!options.inputNameResolver) {
|
|
122
|
-
options.inputNameResolver = defaultInputNameResolver;
|
|
123
|
-
}
|
|
124
|
-
if (!options.customResolver) {
|
|
125
|
-
options.customResolver = new DefaultTypeResolver();
|
|
126
|
-
}
|
|
127
|
-
return options;
|
|
128
|
-
}
|
|
129
|
-
resolve() {
|
|
130
|
-
this.outputResolver = new GraphqlOutputFieldResolver(this.options, this.logger);
|
|
131
|
-
this.inputResolver = new GraphqlInputFieldResolver(this.options, this.logger);
|
|
132
|
-
return {
|
|
133
|
-
query: this.createQueryObject(),
|
|
134
|
-
mutation: this.createMutationObject(),
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
getFields(rootType) {
|
|
138
|
-
const fields = rootType === 'query'
|
|
139
|
-
? {
|
|
140
|
-
description: {
|
|
141
|
-
type: GraphQLString,
|
|
142
|
-
resolve: () => {
|
|
143
|
-
return this.soapEndpoint.description();
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
}
|
|
147
|
-
: {};
|
|
148
|
-
this.soapEndpoint.services().forEach((service) => {
|
|
149
|
-
if (this.options.includeServices) {
|
|
150
|
-
const fieldName = service.name();
|
|
151
|
-
fields[fieldName] = this.createSoapServiceField(service, rootType);
|
|
152
|
-
}
|
|
153
|
-
else if (this.options.includePorts) {
|
|
154
|
-
service.ports().forEach((port) => {
|
|
155
|
-
const fieldName = port.name();
|
|
156
|
-
fields[fieldName] = this.createSoapPortField(service, port, rootType);
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
service.ports().forEach((port) => {
|
|
161
|
-
port.operations().forEach((operation) => {
|
|
162
|
-
const fieldConfig = this.createSoapOperationField(operation, rootType);
|
|
163
|
-
if (fieldConfig) {
|
|
164
|
-
fields[operation.name()] = fieldConfig;
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
return fields;
|
|
171
|
-
}
|
|
172
|
-
createQueryObject() {
|
|
173
|
-
return new GraphQLObjectType({
|
|
174
|
-
name: 'Query',
|
|
175
|
-
fields: () => this.getFields('query'),
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
createMutationObject() {
|
|
179
|
-
return new GraphQLObjectType({
|
|
180
|
-
name: 'Mutation',
|
|
181
|
-
fields: () => this.getFields('mutation'),
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
createSoapServiceField(service, rootType) {
|
|
185
|
-
const fieldsThunk = () => {
|
|
186
|
-
const fields = {};
|
|
187
|
-
service.ports().forEach((port) => {
|
|
188
|
-
if (this.options.includePorts) {
|
|
189
|
-
fields[port.name()] = this.createSoapPortField(service, port, rootType);
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
port.operations().forEach((operation) => {
|
|
193
|
-
const fieldConfig = this.createSoapOperationField(operation, rootType);
|
|
194
|
-
if (fieldConfig) {
|
|
195
|
-
fields[operation.name()] = fieldConfig;
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
return fields;
|
|
201
|
-
};
|
|
202
|
-
const returnType = new GraphQLObjectType({
|
|
203
|
-
name: service.name() + 'Service' + (rootType === 'query' ? 'Query' : ''),
|
|
204
|
-
description: `Service ${service.name()}`,
|
|
205
|
-
fields: fieldsThunk,
|
|
206
|
-
});
|
|
207
|
-
return {
|
|
208
|
-
type: returnType,
|
|
209
|
-
description: `Service ${service.name()}`,
|
|
210
|
-
resolve: () => {
|
|
211
|
-
return {};
|
|
212
|
-
},
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
createSoapPortField(service, port, rootType) {
|
|
216
|
-
const fieldsThunk = () => {
|
|
217
|
-
const fields = {};
|
|
218
|
-
port.operations().forEach((operation) => {
|
|
219
|
-
const fieldConfig = this.createSoapOperationField(operation, rootType);
|
|
220
|
-
if (fieldConfig) {
|
|
221
|
-
fields[operation.name()] = fieldConfig;
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
return fields;
|
|
225
|
-
};
|
|
226
|
-
const returnType = new GraphQLObjectType({
|
|
227
|
-
name: port.name() + 'Port' + (rootType === 'query' ? 'Query' : ''),
|
|
228
|
-
description: `Port ${port.name()}, service ${service.name()}`,
|
|
229
|
-
fields: fieldsThunk,
|
|
230
|
-
});
|
|
231
|
-
return {
|
|
232
|
-
type: returnType,
|
|
233
|
-
description: `Port ${port.name()}, service ${service.name()}`,
|
|
234
|
-
resolve: () => {
|
|
235
|
-
return {};
|
|
236
|
-
},
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
getFieldConfig(operation) {
|
|
240
|
-
const args = this.createSoapOperationFieldArgs(operation);
|
|
241
|
-
const returnType = this.resolveSoapOperationReturnType(operation);
|
|
242
|
-
const resolver = this.createSoapOperationFieldResolver(operation);
|
|
243
|
-
return {
|
|
244
|
-
type: returnType,
|
|
245
|
-
description: `Operation ${operation.name()}, port ${operation.port().name()}, service ${operation
|
|
246
|
-
.service()
|
|
247
|
-
.name()}`,
|
|
248
|
-
args,
|
|
249
|
-
resolve: resolver,
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
createSoapOperationField(operation, rootType) {
|
|
253
|
-
var _a;
|
|
254
|
-
if ((_a = this.options.selectQueryOrMutationField) === null || _a === void 0 ? void 0 : _a.length) {
|
|
255
|
-
const selectionConfig = this.options.selectQueryOrMutationField.find(configElem => configElem.service === operation.service().name() &&
|
|
256
|
-
configElem.port === operation.port().name() &&
|
|
257
|
-
configElem.operation === operation.name());
|
|
258
|
-
if (selectionConfig != null) {
|
|
259
|
-
if (selectionConfig.type === rootType) {
|
|
260
|
-
return this.getFieldConfig(operation);
|
|
261
|
-
}
|
|
262
|
-
else {
|
|
263
|
-
return undefined;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
if (this.options.selectQueryOperationsAuto) {
|
|
268
|
-
if (operation.name().toLowerCase().startsWith('get') ||
|
|
269
|
-
operation.name().toLowerCase().startsWith('find') ||
|
|
270
|
-
operation.name().toLowerCase().startsWith('list') ||
|
|
271
|
-
operation.name().toLowerCase().startsWith('query') ||
|
|
272
|
-
operation.name().toLowerCase().startsWith('search')) {
|
|
273
|
-
if (rootType === 'query') {
|
|
274
|
-
return this.getFieldConfig(operation);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
else {
|
|
278
|
-
if (rootType === 'mutation') {
|
|
279
|
-
return this.getFieldConfig(operation);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
else if (rootType === 'mutation') {
|
|
284
|
-
return this.getFieldConfig(operation);
|
|
285
|
-
}
|
|
286
|
-
return undefined;
|
|
287
|
-
}
|
|
288
|
-
createSoapOperationFieldArgs(operation) {
|
|
289
|
-
const args = {};
|
|
290
|
-
operation.args().forEach((soapField) => {
|
|
291
|
-
args[soapField.name] = {
|
|
292
|
-
type: this.inputResolver.resolve(soapField),
|
|
293
|
-
};
|
|
294
|
-
});
|
|
295
|
-
return args;
|
|
296
|
-
}
|
|
297
|
-
resolveSoapOperationReturnType(operation) {
|
|
298
|
-
return this.outputResolver.resolve(operation.output());
|
|
299
|
-
}
|
|
300
|
-
createSoapOperationFieldResolver(operation) {
|
|
301
|
-
return async (graphqlSource, graphqlArgs, graphqlContext, graphqlInfo) => {
|
|
302
|
-
return this.soapCaller.call({
|
|
303
|
-
operation,
|
|
304
|
-
graphqlSource,
|
|
305
|
-
graphqlArgs,
|
|
306
|
-
graphqlContext,
|
|
307
|
-
graphqlInfo,
|
|
308
|
-
});
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
class GraphqlOutputFieldResolver {
|
|
313
|
-
constructor(options, logger) {
|
|
314
|
-
this.options = options;
|
|
315
|
-
this.logger = logger;
|
|
316
|
-
this.alreadyResolvedOutputTypes = new Map();
|
|
317
|
-
this.alreadyResolvedInterfaceTypes = new Map();
|
|
318
|
-
}
|
|
319
|
-
resolve(input) {
|
|
320
|
-
try {
|
|
321
|
-
const type = this.resolveOutputType(input.type);
|
|
322
|
-
return input.isList ? new GraphQLList(type) : type;
|
|
323
|
-
}
|
|
324
|
-
catch (err) {
|
|
325
|
-
const errStacked = new Error(`could not resolve output type for ${util.inspect(input)}`);
|
|
326
|
-
errStacked.stack += '\nCaused by: ' + err.stack;
|
|
327
|
-
throw errStacked;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
resolveOutputType(soapType) {
|
|
331
|
-
var _a;
|
|
332
|
-
if (this.alreadyResolvedOutputTypes.has(soapType)) {
|
|
333
|
-
return this.alreadyResolvedOutputTypes.get(soapType);
|
|
334
|
-
}
|
|
335
|
-
if (typeof soapType === 'string') {
|
|
336
|
-
const customType = this.options.customResolver.outputType(soapType);
|
|
337
|
-
if (customType) {
|
|
338
|
-
this.alreadyResolvedOutputTypes.set(soapType, customType);
|
|
339
|
-
return customType;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
else if ((soapType === null || soapType === void 0 ? void 0 : soapType.name) && ((_a = soapType === null || soapType === void 0 ? void 0 : soapType.fields) === null || _a === void 0 ? void 0 : _a.length) > 0) {
|
|
343
|
-
const objectType = this.createObjectType(soapType);
|
|
344
|
-
if (objectType) {
|
|
345
|
-
this.alreadyResolvedOutputTypes.set(soapType, objectType);
|
|
346
|
-
return objectType;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
this.logger.warn(`could not resolve output type '`, soapType, `'; using GraphQLJSON instead`);
|
|
350
|
-
this.alreadyResolvedOutputTypes.set(soapType, GraphQLJSON);
|
|
351
|
-
return GraphQLJSON;
|
|
352
|
-
}
|
|
353
|
-
createObjectType(soapType) {
|
|
354
|
-
return new GraphQLObjectType(this.createObjectTypeConfig(soapType));
|
|
355
|
-
}
|
|
356
|
-
createObjectTypeConfig(soapType) {
|
|
357
|
-
const fields = () => {
|
|
358
|
-
const fieldMap = {};
|
|
359
|
-
this.appendObjectTypeFields(fieldMap, soapType);
|
|
360
|
-
return fieldMap;
|
|
361
|
-
};
|
|
362
|
-
const interfaces = () => {
|
|
363
|
-
const interfaces = [];
|
|
364
|
-
this.appendInterfaces(interfaces, soapType);
|
|
365
|
-
return interfaces;
|
|
366
|
-
};
|
|
367
|
-
return {
|
|
368
|
-
name: this.options.outputNameResolver(soapType),
|
|
369
|
-
fields,
|
|
370
|
-
interfaces,
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
appendObjectTypeFields(fieldMap, soapType) {
|
|
374
|
-
soapType.fields.forEach((soapField) => {
|
|
375
|
-
fieldMap[soapField.name] = {
|
|
376
|
-
type: this.resolve(soapField),
|
|
377
|
-
};
|
|
378
|
-
});
|
|
379
|
-
if (soapType.base) {
|
|
380
|
-
this.appendObjectTypeFields(fieldMap, soapType.base);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
appendInterfaces(interfaces, soapType) {
|
|
384
|
-
if (soapType.base) {
|
|
385
|
-
interfaces.push(this.resolveInterfaceType(soapType.base));
|
|
386
|
-
this.appendInterfaces(interfaces, soapType.base);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
resolveInterfaceType(soapType) {
|
|
390
|
-
if (this.alreadyResolvedInterfaceTypes.has(soapType)) {
|
|
391
|
-
return this.alreadyResolvedInterfaceTypes.get(soapType);
|
|
392
|
-
}
|
|
393
|
-
const interfaceType = this.createInterfaceType(soapType);
|
|
394
|
-
this.alreadyResolvedInterfaceTypes.set(soapType, interfaceType);
|
|
395
|
-
return interfaceType;
|
|
396
|
-
}
|
|
397
|
-
createInterfaceType(soapType) {
|
|
398
|
-
return new GraphQLInterfaceType(this.createInterfaceTypeConfig(soapType));
|
|
399
|
-
}
|
|
400
|
-
createInterfaceTypeConfig(soapType) {
|
|
401
|
-
const fields = () => {
|
|
402
|
-
const fieldMap = {};
|
|
403
|
-
this.appendInterfaceTypeFields(fieldMap, soapType);
|
|
404
|
-
return fieldMap;
|
|
405
|
-
};
|
|
406
|
-
return {
|
|
407
|
-
name: this.options.interfaceNameResolver(soapType),
|
|
408
|
-
fields,
|
|
409
|
-
// should never be called, since the schema will not contain ambigous return types
|
|
410
|
-
resolveType: (value, context, info) => {
|
|
411
|
-
throw Error('no interface resolving available');
|
|
412
|
-
},
|
|
413
|
-
};
|
|
414
|
-
}
|
|
415
|
-
appendInterfaceTypeFields(fieldMap, soapType) {
|
|
416
|
-
soapType.fields.forEach((soapField) => {
|
|
417
|
-
fieldMap[soapField.name] = {
|
|
418
|
-
type: this.resolve(soapField),
|
|
419
|
-
};
|
|
420
|
-
});
|
|
421
|
-
if (soapType.base) {
|
|
422
|
-
this.appendObjectTypeFields(fieldMap, soapType.base);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
class GraphqlInputFieldResolver {
|
|
427
|
-
constructor(options, logger) {
|
|
428
|
-
this.options = options;
|
|
429
|
-
this.logger = logger;
|
|
430
|
-
this.alreadyResolved = new Map();
|
|
431
|
-
}
|
|
432
|
-
resolve(input) {
|
|
433
|
-
try {
|
|
434
|
-
const type = this.resolveInputType(input.type);
|
|
435
|
-
return input.isList ? new GraphQLList(type) : type;
|
|
436
|
-
}
|
|
437
|
-
catch (err) {
|
|
438
|
-
const errStacked = new Error(`could not resolve output type for ${util.inspect(input)}`);
|
|
439
|
-
errStacked.stack += '\nCaused by: ' + err.stack;
|
|
440
|
-
throw errStacked;
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
resolveInputType(soapType) {
|
|
444
|
-
var _a;
|
|
445
|
-
if (this.alreadyResolved.has(soapType)) {
|
|
446
|
-
return this.alreadyResolved.get(soapType);
|
|
447
|
-
}
|
|
448
|
-
if (typeof soapType === 'string') {
|
|
449
|
-
const customType = this.options.customResolver.inputType(soapType);
|
|
450
|
-
if (customType) {
|
|
451
|
-
this.alreadyResolved.set(soapType, customType);
|
|
452
|
-
return customType;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
else if ((soapType === null || soapType === void 0 ? void 0 : soapType.name) && ((_a = soapType === null || soapType === void 0 ? void 0 : soapType.fields) === null || _a === void 0 ? void 0 : _a.length) > 0) {
|
|
456
|
-
const objectType = this.createObjectType(soapType);
|
|
457
|
-
if (objectType) {
|
|
458
|
-
this.alreadyResolved.set(soapType, objectType);
|
|
459
|
-
return objectType;
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
this.logger.warn(`could not resolve input type '${soapType}'; using GraphQLString`);
|
|
463
|
-
this.alreadyResolved.set(soapType, GraphQLString);
|
|
464
|
-
return GraphQLString;
|
|
465
|
-
}
|
|
466
|
-
createObjectType(soapType) {
|
|
467
|
-
return new GraphQLInputObjectType(this.createObjectTypeConfig(soapType));
|
|
468
|
-
}
|
|
469
|
-
createObjectTypeConfig(soapType) {
|
|
470
|
-
const fields = () => {
|
|
471
|
-
const fieldMap = {};
|
|
472
|
-
this.appendObjectTypeFields(fieldMap, soapType);
|
|
473
|
-
return fieldMap;
|
|
474
|
-
};
|
|
475
|
-
return {
|
|
476
|
-
name: this.options.inputNameResolver(soapType),
|
|
477
|
-
fields,
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
appendObjectTypeFields(fieldMap, soapType) {
|
|
481
|
-
soapType.fields.forEach((soapField) => {
|
|
482
|
-
fieldMap[soapField.name] = {
|
|
483
|
-
type: this.resolve(soapField),
|
|
484
|
-
};
|
|
485
|
-
});
|
|
486
|
-
if (soapType.base) {
|
|
487
|
-
this.appendObjectTypeFields(fieldMap, soapType.base);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
function createSchemaConfig(endpoint, soapCaller, options = {}, logger) {
|
|
493
|
-
return new SchemaResolver(endpoint, soapCaller, options, logger).resolve();
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
class NodeSoapWsdlResolver {
|
|
497
|
-
constructor(wsdl, logger) {
|
|
498
|
-
this.wsdl = wsdl;
|
|
499
|
-
this.logger = logger;
|
|
500
|
-
this.alreadyResolved = new Map();
|
|
501
|
-
}
|
|
502
|
-
warn(...args) {
|
|
503
|
-
this.logger.warn(...args);
|
|
504
|
-
}
|
|
505
|
-
debug(...args) {
|
|
506
|
-
this.logger.debug(...args);
|
|
507
|
-
}
|
|
508
|
-
createOperationArgs(operation) {
|
|
509
|
-
const inputContent = operation.content().input;
|
|
510
|
-
this.debug(`creating args for operation '${operation.name()}' from content`, inputContent);
|
|
511
|
-
if (!inputContent) {
|
|
512
|
-
this.warn(`no input definition for operation '${operation.name()}'`);
|
|
513
|
-
}
|
|
514
|
-
// inputContent===null -> argNames===[]
|
|
515
|
-
const argNames = nonNamespaceKeys(inputContent);
|
|
516
|
-
const inputNamespace = inputContent && targetNamespace(inputContent);
|
|
517
|
-
const args = argNames
|
|
518
|
-
.map((key) => {
|
|
519
|
-
return this.createOperationArg(operation, inputNamespace, key, inputContent[key]);
|
|
520
|
-
})
|
|
521
|
-
.filter(arg => !!arg);
|
|
522
|
-
return args;
|
|
523
|
-
}
|
|
524
|
-
createOperationArg(operation, inputNamespace, argWsdlFieldName, argContent) {
|
|
525
|
-
this.debug(`creating arg for operation '${operation.name()}' from content `, argContent);
|
|
526
|
-
const parsedArgName = parseWsdlFieldName(argWsdlFieldName);
|
|
527
|
-
const inputType = this.resolveContentToSoapType(inputNamespace, argContent, `arg '${argWsdlFieldName}' of operation '${operation.name()}'`);
|
|
528
|
-
const input = {
|
|
529
|
-
name: parsedArgName.name,
|
|
530
|
-
type: inputType,
|
|
531
|
-
isList: parsedArgName.isList,
|
|
532
|
-
};
|
|
533
|
-
return input;
|
|
534
|
-
}
|
|
535
|
-
createOperationOutput(operation) {
|
|
536
|
-
const outputContent = operation.content().output;
|
|
537
|
-
this.debug(`creating output for operation '${operation.name()}' from content `, outputContent);
|
|
538
|
-
// determine type and field name
|
|
539
|
-
let resultType;
|
|
540
|
-
let resultFieldName;
|
|
541
|
-
const outputNamespace = targetNamespace(outputContent);
|
|
542
|
-
const ownerStringForLog = `output of operation '${operation.name()}'`;
|
|
543
|
-
if (!outputContent) {
|
|
544
|
-
this.warn(`no definition for output type of operation '${operation.name()}', using 'string'`);
|
|
545
|
-
resultType = this.resolveContentToSoapType(outputNamespace, 'string', ownerStringForLog);
|
|
546
|
-
}
|
|
547
|
-
else {
|
|
548
|
-
const outputContentKeys = nonNamespaceKeys(outputContent);
|
|
549
|
-
if (outputContentKeys.length <= 0) {
|
|
550
|
-
// content has no sub content
|
|
551
|
-
// void operation; use String as result type. when executed, it will return null
|
|
552
|
-
resultFieldName = null;
|
|
553
|
-
resultType = this.resolveContentToSoapType(outputNamespace, 'string', ownerStringForLog);
|
|
554
|
-
}
|
|
555
|
-
else {
|
|
556
|
-
if (outputContentKeys.length > 1) {
|
|
557
|
-
// content has multiple fields, use the first one
|
|
558
|
-
// @todo maybe better build an extra type for this case, but how to name it?
|
|
559
|
-
this.warn(`multiple result fields in output definition of operation '${operation.name()}', using first one`);
|
|
560
|
-
}
|
|
561
|
-
resultFieldName = outputContentKeys[0];
|
|
562
|
-
const resultContent = outputContent[resultFieldName];
|
|
563
|
-
if (!resultContent) {
|
|
564
|
-
this.warn(`no type definition for result field '${resultFieldName}' in output definition for operation '${operation.name()}', using 'string'`);
|
|
565
|
-
resultType = this.resolveContentToSoapType(outputNamespace, 'string', ownerStringForLog);
|
|
566
|
-
}
|
|
567
|
-
else {
|
|
568
|
-
resultType = this.resolveContentToSoapType(outputNamespace, resultContent, ownerStringForLog);
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
const parsedResultFieldName = parseWsdlFieldName(resultFieldName);
|
|
573
|
-
return {
|
|
574
|
-
type: {
|
|
575
|
-
type: resultType,
|
|
576
|
-
isList: parsedResultFieldName.isList,
|
|
577
|
-
},
|
|
578
|
-
resultField: parsedResultFieldName.name,
|
|
579
|
-
};
|
|
580
|
-
}
|
|
581
|
-
resolveContentToSoapType(parentNamespace, typeContent, ownerStringForLog) {
|
|
582
|
-
this.debug(`resolving soap type for ${ownerStringForLog} from content `, typeContent);
|
|
583
|
-
// determine name of the type
|
|
584
|
-
let wsdlTypeName;
|
|
585
|
-
let namespace;
|
|
586
|
-
if (!typeContent) {
|
|
587
|
-
this.warn(`no type definition for ${ownerStringForLog}, using 'string'`);
|
|
588
|
-
wsdlTypeName = 'string';
|
|
589
|
-
namespace = parentNamespace;
|
|
590
|
-
}
|
|
591
|
-
else if (typeof typeContent === 'string') {
|
|
592
|
-
// primitive type
|
|
593
|
-
wsdlTypeName = withoutNamespace(typeContent);
|
|
594
|
-
namespace = parentNamespace;
|
|
595
|
-
}
|
|
596
|
-
else {
|
|
597
|
-
wsdlTypeName = this.findTypeName(typeContent);
|
|
598
|
-
if (!wsdlTypeName) {
|
|
599
|
-
this.warn(`no type name found for ${ownerStringForLog}, using 'string'`);
|
|
600
|
-
wsdlTypeName = 'string';
|
|
601
|
-
}
|
|
602
|
-
namespace = targetNamespace(typeContent);
|
|
603
|
-
}
|
|
604
|
-
return this.resolveWsdlNameToSoapType(namespace, wsdlTypeName, ownerStringForLog);
|
|
605
|
-
}
|
|
606
|
-
findTypeName(content) {
|
|
607
|
-
const types = this.wsdl.definitions.descriptions.types;
|
|
608
|
-
for (const key in types) {
|
|
609
|
-
if (types[key] === content) {
|
|
610
|
-
return key;
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
return null;
|
|
614
|
-
}
|
|
615
|
-
resolveWsdlNameToSoapType(namespace, wsdlTypeName, ownerStringForLog) {
|
|
616
|
-
var _a;
|
|
617
|
-
this.debug(() => `resolving soap type for ${ownerStringForLog} from namespace '${namespace}', type name '${wsdlTypeName}'`);
|
|
618
|
-
// lookup cache; this accomplishes three things:
|
|
619
|
-
// 1) an incredible boost in performance, must be at least 3ns, !!hax0r!!11
|
|
620
|
-
// 2) every type definition (primitive and complex) has only one instance of SoapType
|
|
621
|
-
// 3) resolve circular dependencies between types
|
|
622
|
-
if (this.alreadyResolved.has(namespace + wsdlTypeName)) {
|
|
623
|
-
this.debug(`resolved soap type for namespace: '${namespace}', typeName: '${wsdlTypeName}' from cache`);
|
|
624
|
-
return this.alreadyResolved.get(namespace + wsdlTypeName);
|
|
625
|
-
}
|
|
626
|
-
// get the defition of the type from the schema section in the WSDL
|
|
627
|
-
const xsdTypeDefinition = this.findXsdTypeDefinition(namespace, wsdlTypeName);
|
|
628
|
-
if (!((_a = xsdTypeDefinition === null || xsdTypeDefinition === void 0 ? void 0 : xsdTypeDefinition.children) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
629
|
-
// has no type definition
|
|
630
|
-
// --> primitive type, e.g. 'string'
|
|
631
|
-
const soapType = wsdlTypeName;
|
|
632
|
-
this.alreadyResolved.set(namespace + wsdlTypeName, soapType);
|
|
633
|
-
this.debug(() => `resolved namespace: '${namespace}', typeName: '${wsdlTypeName}' to primitive type '${soapType}'`);
|
|
634
|
-
return soapType;
|
|
635
|
-
}
|
|
636
|
-
else {
|
|
637
|
-
// create a new object type
|
|
638
|
-
const soapType = {
|
|
639
|
-
name: xsdTypeDefinition.$name,
|
|
640
|
-
base: null,
|
|
641
|
-
fields: null,
|
|
642
|
-
};
|
|
643
|
-
this.alreadyResolved.set(namespace + wsdlTypeName, soapType);
|
|
644
|
-
// resolve bindings (field types, base type) after type has been registered to resolve circular dependencies
|
|
645
|
-
this.resolveTypeBody(soapType, namespace, xsdTypeDefinition);
|
|
646
|
-
this.debug(`resolved namespace: '${namespace}', typeName: '${wsdlTypeName}' to object type `, soapType);
|
|
647
|
-
return soapType;
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
findXsdTypeDefinition(namespace, typeName) {
|
|
651
|
-
return this.wsdl.findSchemaObject(namespace, typeName);
|
|
652
|
-
}
|
|
653
|
-
resolveTypeBody(soapType, namespace, typeDefinition) {
|
|
654
|
-
this.debug(`resolving body of soap type '${soapType.name}' from namespace '${namespace}', definition`, typeDefinition);
|
|
655
|
-
const typeName = typeDefinition.$name;
|
|
656
|
-
let fields = null;
|
|
657
|
-
let baseTypeName = null;
|
|
658
|
-
const body = typeDefinition.children[0];
|
|
659
|
-
if (body.name === 'sequence') {
|
|
660
|
-
const sequence = body;
|
|
661
|
-
fields = sequence.children || [];
|
|
662
|
-
}
|
|
663
|
-
else if (body.name === 'complexContent') {
|
|
664
|
-
const extension = body.children[0];
|
|
665
|
-
const sequence = extension.children[0];
|
|
666
|
-
baseTypeName = withoutNamespace(extension.$base);
|
|
667
|
-
fields = sequence.children || [];
|
|
668
|
-
}
|
|
669
|
-
else {
|
|
670
|
-
this.warn(`cannot parse fields for soap type '${typeName}', leaving fields empty`);
|
|
671
|
-
fields = [];
|
|
672
|
-
}
|
|
673
|
-
const soapFields = fields
|
|
674
|
-
.filter(field => field.$name)
|
|
675
|
-
.map((field) => {
|
|
676
|
-
return {
|
|
677
|
-
name: field.$name,
|
|
678
|
-
type: this.resolveWsdlNameToSoapType(field.$targetNamespace, withoutNamespace(field.$type), `field '${field.$name}' of soap type '${soapType.name}'`),
|
|
679
|
-
isList: !!field.$maxOccurs && field.$maxOccurs === 'unbounded',
|
|
680
|
-
};
|
|
681
|
-
});
|
|
682
|
-
// @todo in XSD it is possible to inherit a type from a primitive ... may have to handle this
|
|
683
|
-
const baseType = !baseTypeName
|
|
684
|
-
? null
|
|
685
|
-
: (this.resolveWsdlNameToSoapType(namespace, baseTypeName, `base type of soap type '${soapType.name}'`));
|
|
686
|
-
soapType.fields = soapFields;
|
|
687
|
-
soapType.base = baseType;
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
function nonNamespaceKeys(obj) {
|
|
691
|
-
return !obj ? [] : Object.keys(obj).filter(key => !isNamespaceKey(key.toString()));
|
|
692
|
-
}
|
|
693
|
-
function targetNamespace(content) {
|
|
694
|
-
return content.targetNamespace;
|
|
695
|
-
}
|
|
696
|
-
function isNamespaceKey(key) {
|
|
697
|
-
return key === 'targetNSAlias' || key === 'targetNamespace';
|
|
698
|
-
}
|
|
699
|
-
function withoutNamespace(value) {
|
|
700
|
-
if (!value) {
|
|
701
|
-
return value;
|
|
702
|
-
}
|
|
703
|
-
const matcher = value.match(/[a-zA-Z0-9]+\:(.+)/);
|
|
704
|
-
return !matcher || matcher.length < 2 ? value : matcher[1];
|
|
705
|
-
}
|
|
706
|
-
function isWsdlListFieldName(wsdlFieldName) {
|
|
707
|
-
return !!wsdlFieldName && wsdlFieldName.endsWith('[]');
|
|
708
|
-
}
|
|
709
|
-
function parseWsdlFieldName(wsdlFieldName) {
|
|
710
|
-
if (isWsdlListFieldName(wsdlFieldName)) {
|
|
711
|
-
return {
|
|
712
|
-
name: wsdlFieldName.substring(0, wsdlFieldName.length - 2),
|
|
713
|
-
isList: true,
|
|
714
|
-
};
|
|
715
|
-
}
|
|
716
|
-
else {
|
|
717
|
-
return {
|
|
718
|
-
name: wsdlFieldName,
|
|
719
|
-
isList: false,
|
|
720
|
-
};
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
function createSoapEndpoint(soapClient, logger) {
|
|
725
|
-
return new NodeSoapEndpoint(soapClient, logger);
|
|
726
|
-
}
|
|
727
|
-
class NodeSoapEndpoint {
|
|
728
|
-
constructor(soapClient, logger) {
|
|
729
|
-
this.soapClient = soapClient;
|
|
730
|
-
this._describe = null;
|
|
731
|
-
this._resolver = new NodeSoapWsdlResolver(this.soapClient.wsdl, logger);
|
|
732
|
-
}
|
|
733
|
-
description() {
|
|
734
|
-
return this.soapClient.wsdl.toXML();
|
|
735
|
-
}
|
|
736
|
-
services() {
|
|
737
|
-
const services = [];
|
|
738
|
-
const content = this.describe();
|
|
739
|
-
for (const key in content) {
|
|
740
|
-
services.push(new NodeSoapService(this, key, content[key]));
|
|
741
|
-
}
|
|
742
|
-
return services;
|
|
743
|
-
}
|
|
744
|
-
resolver() {
|
|
745
|
-
return this._resolver;
|
|
746
|
-
}
|
|
747
|
-
describe() {
|
|
748
|
-
if (!this._describe) {
|
|
749
|
-
this._describe = this.soapClient.describe();
|
|
750
|
-
}
|
|
751
|
-
return this._describe;
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
class NodeSoapService {
|
|
755
|
-
constructor(_wsdl, _name, _content) {
|
|
756
|
-
this._wsdl = _wsdl;
|
|
757
|
-
this._name = _name;
|
|
758
|
-
this._content = _content;
|
|
759
|
-
this._ports = null;
|
|
760
|
-
}
|
|
761
|
-
endpoint() {
|
|
762
|
-
return this._wsdl;
|
|
763
|
-
}
|
|
764
|
-
name() {
|
|
765
|
-
return this._name;
|
|
766
|
-
}
|
|
767
|
-
ports() {
|
|
768
|
-
if (!this._ports) {
|
|
769
|
-
this._ports = this.createPorts();
|
|
770
|
-
}
|
|
771
|
-
return this._ports;
|
|
772
|
-
}
|
|
773
|
-
createPorts() {
|
|
774
|
-
const ports = [];
|
|
775
|
-
for (const key in this._content) {
|
|
776
|
-
ports.push(new NodeSoapPort(this, key, this._content[key]));
|
|
777
|
-
}
|
|
778
|
-
return ports;
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
class NodeSoapPort {
|
|
782
|
-
constructor(_service, _name, _content) {
|
|
783
|
-
this._service = _service;
|
|
784
|
-
this._name = _name;
|
|
785
|
-
this._content = _content;
|
|
786
|
-
this._operations = null;
|
|
787
|
-
}
|
|
788
|
-
endpoint() {
|
|
789
|
-
return this.service().endpoint();
|
|
790
|
-
}
|
|
791
|
-
service() {
|
|
792
|
-
return this._service;
|
|
793
|
-
}
|
|
794
|
-
name() {
|
|
795
|
-
return this._name;
|
|
796
|
-
}
|
|
797
|
-
operations() {
|
|
798
|
-
if (!this._operations) {
|
|
799
|
-
this._operations = this.createOperations();
|
|
800
|
-
}
|
|
801
|
-
return this._operations;
|
|
802
|
-
}
|
|
803
|
-
createOperations() {
|
|
804
|
-
const operations = [];
|
|
805
|
-
for (const key in this._content) {
|
|
806
|
-
operations.push(new NodeSoapOperation(this, key, this._content[key]));
|
|
807
|
-
}
|
|
808
|
-
return operations;
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
class NodeSoapOperation {
|
|
812
|
-
constructor(_port, _name, _content) {
|
|
813
|
-
this._port = _port;
|
|
814
|
-
this._name = _name;
|
|
815
|
-
this._content = _content;
|
|
816
|
-
this._inputs = null;
|
|
817
|
-
this._output = null;
|
|
818
|
-
}
|
|
819
|
-
endpoint() {
|
|
820
|
-
return this.port().endpoint();
|
|
821
|
-
}
|
|
822
|
-
service() {
|
|
823
|
-
return this.port().service();
|
|
824
|
-
}
|
|
825
|
-
port() {
|
|
826
|
-
return this._port;
|
|
827
|
-
}
|
|
828
|
-
name() {
|
|
829
|
-
return this._name;
|
|
830
|
-
}
|
|
831
|
-
content() {
|
|
832
|
-
return this._content;
|
|
833
|
-
}
|
|
834
|
-
args() {
|
|
835
|
-
if (!this._inputs) {
|
|
836
|
-
this._inputs = this.endpoint().resolver().createOperationArgs(this);
|
|
837
|
-
}
|
|
838
|
-
return this._inputs;
|
|
839
|
-
}
|
|
840
|
-
output() {
|
|
841
|
-
if (!this._output) {
|
|
842
|
-
this._output = this.createOutput();
|
|
843
|
-
}
|
|
844
|
-
return this._output.type;
|
|
845
|
-
}
|
|
846
|
-
resultField() {
|
|
847
|
-
if (!this._output) {
|
|
848
|
-
this._output = this.createOutput();
|
|
849
|
-
}
|
|
850
|
-
return this._output.resultField;
|
|
851
|
-
}
|
|
852
|
-
createOutput() {
|
|
853
|
-
return this.endpoint().resolver().createOperationOutput(this);
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
/**
|
|
858
|
-
* Default implementation of SoapCaller for node-soap.
|
|
859
|
-
*/
|
|
860
|
-
class NodeSoapCaller {
|
|
861
|
-
constructor(soapClient, logger) {
|
|
862
|
-
this.soapClient = soapClient;
|
|
863
|
-
this.logger = logger;
|
|
864
|
-
}
|
|
865
|
-
async call(input) {
|
|
866
|
-
this.debug(() => [`call operation '${input.operation.name()}' with args '`, input.graphqlArgs]);
|
|
867
|
-
const requestFunction = util.promisify(this.requestFunctionForOperation(input.operation).bind(this));
|
|
868
|
-
const requestMessage = await this.createSoapRequestMessage(input);
|
|
869
|
-
const res = await requestFunction(requestMessage);
|
|
870
|
-
return this.createGraphqlResult(input, res);
|
|
871
|
-
}
|
|
872
|
-
requestFunctionForOperation(operation) {
|
|
873
|
-
return this.soapClient[operation.service().name()][operation.port().name()][operation.name()];
|
|
874
|
-
}
|
|
875
|
-
async createSoapRequestMessage(input) {
|
|
876
|
-
const requestMessage = {};
|
|
877
|
-
Array.from(Object.keys(input.graphqlArgs)).forEach(key => {
|
|
878
|
-
// objects provided by GraphQL will usually lack default-functions like "hasOwnProperty"
|
|
879
|
-
// so deep-copy all objects to ensure those functions are present
|
|
880
|
-
requestMessage[key] = this.deepCopy(input.graphqlArgs[key]);
|
|
881
|
-
});
|
|
882
|
-
return requestMessage;
|
|
883
|
-
}
|
|
884
|
-
deepCopy(obj) {
|
|
885
|
-
if (!obj) {
|
|
886
|
-
return null;
|
|
887
|
-
}
|
|
888
|
-
else if (Object(obj) !== obj) {
|
|
889
|
-
// primitive
|
|
890
|
-
return obj;
|
|
891
|
-
}
|
|
892
|
-
else if (Array.isArray(obj)) {
|
|
893
|
-
return obj.map(e => this.deepCopy(e));
|
|
894
|
-
}
|
|
895
|
-
else {
|
|
896
|
-
const corrected = Object.assign({}, obj);
|
|
897
|
-
Array.from(Object.keys(corrected)).forEach(key => {
|
|
898
|
-
const value = corrected[key];
|
|
899
|
-
corrected[key] = this.deepCopy(value);
|
|
900
|
-
});
|
|
901
|
-
return corrected;
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
async createGraphqlResult(input, result) {
|
|
905
|
-
this.debug(() => [`operation '${input.operation.name()}' returned `, result]);
|
|
906
|
-
if (!input.operation.resultField()) {
|
|
907
|
-
// void operation
|
|
908
|
-
return !result ? null : JSON.stringify(result);
|
|
909
|
-
}
|
|
910
|
-
else {
|
|
911
|
-
return !result ? null : result[input.operation.resultField()];
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
debug(message) {
|
|
915
|
-
this.logger.debug(message);
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
/**
|
|
920
|
-
* Creates a GraphQL schema for the WSDL defined by the given parameters.
|
|
921
|
-
*
|
|
922
|
-
* The created GraphQL schema will include:
|
|
923
|
-
* - A Mutation-field for every operation in the WSDL.
|
|
924
|
-
* If the field is queried via GraphQL, the SOAP endpoint declared in the WSDL will be called and the result of the call will be returned via GraphQL.
|
|
925
|
-
* - A GraphQL output type for every WSDL type that is: a) used as a result of an operation and b) declared in the schema section of the WSDL.
|
|
926
|
-
* - A GraphQL interface type for every WSDL type that is: a) used as a base type of another type and b) declared in the schema section of the WSDL.
|
|
927
|
-
* - A GraphQL input type for every WSDL type that is: a) used as a input type of an operation and b) declared in the schema section of the WSDL.
|
|
928
|
-
* - A Query-field that returns the content of the WSDL (this is necessary, since a GraphQL schema must include at least one Query-field)
|
|
929
|
-
*
|
|
930
|
-
* @param options either an instance of SoapGraphQLOptions or the URL (http/https or path to a file) to a WSDL.
|
|
931
|
-
*/
|
|
932
|
-
async function soapGraphqlSchema(options) {
|
|
933
|
-
return new GraphQLSchema(await soapGraphqlSchemaConfig(options));
|
|
934
|
-
}
|
|
935
|
-
async function soapGraphqlSchemaConfig(options) {
|
|
936
|
-
const soapClient = await useSoapClient(options);
|
|
937
|
-
const wsdl = await createSoapEndpoint(soapClient, options.logger);
|
|
938
|
-
if (!options.soapCaller) {
|
|
939
|
-
options.soapCaller = new NodeSoapCaller(soapClient, options.logger);
|
|
940
|
-
}
|
|
941
|
-
return createSchemaConfig(wsdl, options.soapCaller, options.schemaOptions, options.logger);
|
|
942
|
-
}
|
|
943
|
-
async function useSoapClient(options) {
|
|
944
|
-
if (options.soapClient) {
|
|
945
|
-
return options.soapClient;
|
|
946
|
-
}
|
|
947
|
-
if (options.createClient) {
|
|
948
|
-
return createSoapClient(options.createClient.url, options.createClient.options);
|
|
949
|
-
}
|
|
950
|
-
throw new Error('neither soap client nor node-soap creation options provided');
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
class SoapHandler {
|
|
954
|
-
constructor({ config, baseDir, fetchFn, store, importFn, logger }) {
|
|
955
|
-
this.config = config;
|
|
956
|
-
this.baseDir = baseDir;
|
|
957
|
-
this.fetchFn = fetchFn;
|
|
958
|
-
this.wsdlResponse = store.proxy('wsdlResponse.json', PredefinedProxyOptions.JsonWithoutValidation);
|
|
959
|
-
this.importFn = importFn;
|
|
960
|
-
this.logger = logger;
|
|
961
|
-
}
|
|
962
|
-
async getMeshSource() {
|
|
963
|
-
let schemaHeaders = typeof this.config.schemaHeaders === 'string'
|
|
964
|
-
? await loadFromModuleExportExpression(this.config.schemaHeaders, {
|
|
965
|
-
cwd: this.baseDir,
|
|
966
|
-
defaultExportName: 'default',
|
|
967
|
-
importFn: this.importFn,
|
|
968
|
-
})
|
|
969
|
-
: this.config.schemaHeaders;
|
|
970
|
-
if (typeof schemaHeaders === 'function') {
|
|
971
|
-
schemaHeaders = schemaHeaders();
|
|
972
|
-
}
|
|
973
|
-
if (schemaHeaders && 'then' in schemaHeaders) {
|
|
974
|
-
schemaHeaders = await schemaHeaders;
|
|
975
|
-
}
|
|
976
|
-
const soapClient = await createSoapClient(this.config.wsdl, {
|
|
977
|
-
basicAuth: this.config.basicAuth,
|
|
978
|
-
options: {
|
|
979
|
-
request: (async (requestObj) => {
|
|
980
|
-
const isWsdlRequest = requestObj.url === this.config.wsdl;
|
|
981
|
-
const sendRequest = async () => {
|
|
982
|
-
const headers = {
|
|
983
|
-
...requestObj.headers,
|
|
984
|
-
...(isWsdlRequest ? schemaHeaders : this.config.operationHeaders),
|
|
985
|
-
};
|
|
986
|
-
delete headers.Connection;
|
|
987
|
-
const res = await this.fetchFn(requestObj.url, {
|
|
988
|
-
headers,
|
|
989
|
-
method: requestObj.method,
|
|
990
|
-
body: requestObj.data,
|
|
991
|
-
});
|
|
992
|
-
const data = await res.text();
|
|
993
|
-
return {
|
|
994
|
-
data,
|
|
995
|
-
status: res.status,
|
|
996
|
-
statusText: res.statusText,
|
|
997
|
-
headers: getHeadersObj(res.headers),
|
|
998
|
-
config: requestObj,
|
|
999
|
-
};
|
|
1000
|
-
};
|
|
1001
|
-
if (isWsdlRequest) {
|
|
1002
|
-
return this.wsdlResponse.getWithSet(() => sendRequest());
|
|
1003
|
-
}
|
|
1004
|
-
return sendRequest();
|
|
1005
|
-
}),
|
|
1006
|
-
},
|
|
1007
|
-
});
|
|
1008
|
-
if (this.config.securityCert) {
|
|
1009
|
-
const securityCertConfig = this.config.securityCert;
|
|
1010
|
-
const [privateKey, publicKey, password] = await Promise.all([
|
|
1011
|
-
securityCertConfig.privateKey ||
|
|
1012
|
-
(securityCertConfig.privateKeyPath &&
|
|
1013
|
-
readFileOrUrl(securityCertConfig.privateKeyPath, {
|
|
1014
|
-
allowUnknownExtensions: true,
|
|
1015
|
-
cwd: this.baseDir,
|
|
1016
|
-
importFn: this.importFn,
|
|
1017
|
-
fetch: this.fetchFn,
|
|
1018
|
-
logger: this.logger,
|
|
1019
|
-
})),
|
|
1020
|
-
securityCertConfig.publicKey ||
|
|
1021
|
-
(securityCertConfig.publicKeyPath &&
|
|
1022
|
-
readFileOrUrl(securityCertConfig.publicKeyPath, {
|
|
1023
|
-
allowUnknownExtensions: true,
|
|
1024
|
-
cwd: this.baseDir,
|
|
1025
|
-
importFn: this.importFn,
|
|
1026
|
-
fetch: this.fetchFn,
|
|
1027
|
-
logger: this.logger,
|
|
1028
|
-
})),
|
|
1029
|
-
securityCertConfig.password ||
|
|
1030
|
-
(securityCertConfig.passwordPath &&
|
|
1031
|
-
readFileOrUrl(securityCertConfig.passwordPath, {
|
|
1032
|
-
allowUnknownExtensions: true,
|
|
1033
|
-
cwd: this.baseDir,
|
|
1034
|
-
importFn: this.importFn,
|
|
1035
|
-
fetch: this.fetchFn,
|
|
1036
|
-
logger: this.logger,
|
|
1037
|
-
})),
|
|
1038
|
-
]);
|
|
1039
|
-
soapClient.setSecurity(new soap.WSSecurityCert(privateKey, publicKey, password));
|
|
1040
|
-
}
|
|
1041
|
-
const schema = await soapGraphqlSchema({
|
|
1042
|
-
soapClient,
|
|
1043
|
-
logger: this.logger,
|
|
1044
|
-
debug: !!process.env.DEBUG,
|
|
1045
|
-
warnings: !!process.env.DEBUG,
|
|
1046
|
-
schemaOptions: {
|
|
1047
|
-
includePorts: this.config.includePorts,
|
|
1048
|
-
includeServices: this.config.includeServices,
|
|
1049
|
-
selectQueryOrMutationField: this.config.selectQueryOrMutationField,
|
|
1050
|
-
selectQueryOperationsAuto: this.config.selectQueryOperationsAuto,
|
|
1051
|
-
},
|
|
1052
|
-
});
|
|
1053
|
-
return {
|
|
1054
|
-
schema,
|
|
1055
|
-
};
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
export default SoapHandler;
|