@omnigraph/json-schema
Version:
This package generates GraphQL Schema from JSON Schema and sample JSON request and responses. You can define your root field endpoints like below in your GraphQL Config for example;
2,364 lines • 115 kB
JavaScript
import { DefaultLogger, readFileOrUrl, defaultImportFn, sanitizeNameForGraphQL, getHeadersObj } from '@graphql-mesh/utils';
import { getInterpolationKeys, getInterpolatedHeadersFactory, stringInterpolator } from '@graphql-mesh/string-interpolation';
import { AnySchema, dereferenceObject, healJSONSchema, resolvePath, visitJSONSchema, referenceJSONSchema } from 'json-machete';
import toJsonSchema from 'to-json-schema';
import { process as process$1, util } from '@graphql-mesh/cross-helpers';
import { isListType, isNonNullType, isInputObjectType, GraphQLObjectType, GraphQLString, GraphQLInt, GraphQLError, getNamedType, isScalarType, isUnionType, GraphQLScalarType, Kind, GraphQLFloat, GraphQLBoolean, specifiedDirectives } from 'graphql';
import { GraphQLJSON, isSomeInputTypeComposer, ListComposer, SchemaComposer, ScalarTypeComposer, EnumTypeComposer, UnionTypeComposer, InterfaceTypeComposer, ObjectTypeComposer } from 'graphql-compose';
import { asArray, memoize1, inspect, memoize2 } from '@graphql-tools/utils';
import urlJoin from 'url-join';
import { stringify, parse } from 'qs';
import lodashSet from 'lodash.set';
import { FormData, File, Blob, fetch } from '@whatwg-node/fetch';
import { GraphQLJSON as GraphQLJSON$1, RegularExpression, GraphQLBigInt, GraphQLTimestamp, GraphQLUUID, GraphQLURL, GraphQLIPv6, GraphQLIPv4, GraphQLEmailAddress, GraphQLTime, GraphQLDateTime, GraphQLByte, GraphQLNonNegativeInt, GraphQLNonNegativeFloat, GraphQLPositiveInt, GraphQLPositiveFloat, GraphQLNonPositiveInt, GraphQLNonPositiveFloat, GraphQLNegativeInt, GraphQLNegativeFloat, GraphQLNonEmptyString } from 'graphql-scalars';
import Ajv from 'ajv';
import addFormats from 'ajv-formats';
import { pascalCase } from 'pascal-case';
function isPubSubOperationConfig(operationConfig) {
return 'pubsubTopic' in operationConfig;
}
function getOperationMetadata(operationConfig) {
let httpMethod;
let operationType;
let rootTypeName;
if (isPubSubOperationConfig(operationConfig)) {
httpMethod = null;
operationType = 'subscription';
rootTypeName = 'Subscription';
}
else {
httpMethod = operationConfig.method;
// Fix compability with Mesh handler
operationType = operationConfig.type.toLowerCase();
if (!httpMethod) {
if (operationType === 'mutation') {
httpMethod = 'POST';
}
else {
httpMethod = 'GET';
}
}
if (!rootTypeName) {
if (httpMethod === 'GET') {
rootTypeName = 'Query';
}
}
rootTypeName = operationType === 'query' ? 'Query' : 'Mutation';
}
return {
httpMethod,
operationType,
rootTypeName,
fieldName: operationConfig.field,
};
}
function isFileUpload(obj) {
return typeof obj.createReadStream === 'function';
}
async function handleOperationResponseConfig(operationResponseConfig, { schemaHeaders, cwd, fetchFn, logger = new DefaultLogger('handleOperationResponseConfig'), }) {
if (operationResponseConfig.responseSchema) {
const schema = typeof operationResponseConfig.responseSchema === 'string'
? {
$ref: operationResponseConfig.responseSchema,
title: operationResponseConfig.responseTypeName,
}
: operationResponseConfig.responseSchema;
if (operationResponseConfig.responseSample) {
schema.examples = schema.examples || [operationResponseConfig.responseSample];
}
return schema;
}
else if (operationResponseConfig.responseSample) {
const sample = typeof operationResponseConfig.responseSample === 'object'
? operationResponseConfig.responseSample
: await readFileOrUrl(operationResponseConfig.responseSample, {
cwd,
fetch: fetchFn,
logger,
importFn: defaultImportFn,
headers: schemaHeaders,
}).catch((e) => {
throw new Error(`responseSample - ${e.message}`);
});
const generatedSchema = toJsonSchema(sample, {
required: false,
objects: {
additionalProperties: false,
},
strings: {
detectFormat: true,
},
arrays: {
mode: 'first',
},
});
generatedSchema.title = operationResponseConfig.responseTypeName;
generatedSchema.examples = [sample];
return generatedSchema;
}
else {
return AnySchema;
}
}
async function getReferencedJSONSchemaFromOperations({ operations, cwd, schemaHeaders, ignoreErrorResponses, logger = new DefaultLogger('getReferencedJSONSchemaFromOperations'), fetchFn, baseUrl, operationHeaders, queryParams, }) {
const finalJsonSchema = {
type: 'object',
title: '_schema',
properties: {},
required: ['query'],
};
for (const operationConfig of operations) {
const { operationType, rootTypeName, fieldName } = getOperationMetadata(operationConfig);
const rootTypeDefinition = (finalJsonSchema.properties[operationType] = finalJsonSchema.properties[operationType] || {
type: 'object',
title: rootTypeName,
properties: {},
readOnly: true,
});
rootTypeDefinition.properties = rootTypeDefinition.properties || {};
const interpolationStrings = [
...Object.values(operationHeaders || {}),
...Object.values(queryParams || {}).map(val => val.toString()),
baseUrl,
];
if ('pubsubTopic' in operationConfig) {
interpolationStrings.push(operationConfig.pubsubTopic);
}
if ('headers' in operationConfig) {
interpolationStrings.push(...Object.values(operationConfig.headers || {}));
}
if ('path' in operationConfig) {
interpolationStrings.push(operationConfig.path);
}
if ('responseByStatusCode' in operationConfig) {
rootTypeDefinition.properties[fieldName] = rootTypeDefinition.properties[fieldName] || {};
const statusCodeOneOfIndexMap = {};
const responseSchemas = [];
for (const statusCode in operationConfig.responseByStatusCode) {
if (ignoreErrorResponses && !statusCode.startsWith('2')) {
continue;
}
const responseOperationConfig = operationConfig.responseByStatusCode[statusCode];
const responseOperationSchema = await handleOperationResponseConfig(responseOperationConfig, {
cwd,
schemaHeaders,
fetchFn,
logger,
});
statusCodeOneOfIndexMap[statusCode] = responseSchemas.length;
responseOperationSchema.title = responseOperationSchema.title || `${fieldName}_${statusCode}_response`;
responseSchemas.push(responseOperationSchema);
}
if (responseSchemas.length === 1) {
rootTypeDefinition.properties[fieldName] = responseSchemas[0];
}
else if (responseSchemas.length === 0) {
rootTypeDefinition.properties[fieldName] = AnySchema;
}
else {
rootTypeDefinition.properties[fieldName] = {
$comment: `statusCodeOneOfIndexMap:${JSON.stringify(statusCodeOneOfIndexMap)}`,
title: fieldName + '_response',
oneOf: responseSchemas,
};
}
}
else {
rootTypeDefinition.properties[fieldName] = await handleOperationResponseConfig(operationConfig, {
cwd,
schemaHeaders,
fetchFn,
logger,
});
}
const rootTypeInputPropertyName = operationType + 'Input';
const rootInputTypeName = rootTypeName + 'Input';
const rootTypeInputTypeDefinition = (finalJsonSchema.properties[rootTypeInputPropertyName] = finalJsonSchema
.properties[rootTypeInputPropertyName] || {
type: 'object',
title: rootInputTypeName,
properties: {},
writeOnly: true,
});
const interpolationKeys = getInterpolationKeys(...interpolationStrings);
if ('queryParamArgMap' in operationConfig) {
interpolationKeys.push(...Object.values(operationConfig.queryParamArgMap).map(key => `args.${key}`));
}
for (const interpolationKey of interpolationKeys) {
const interpolationKeyParts = interpolationKey.split('.');
const initialObjectName = interpolationKeyParts.shift();
if (initialObjectName === 'args') {
rootTypeInputTypeDefinition.properties[fieldName] = rootTypeInputTypeDefinition.properties[fieldName] || {
title: `${rootTypeInputPropertyName}_${fieldName}`,
type: 'object',
properties: {},
};
const varName = interpolationKeyParts.shift();
if (operationConfig.argTypeMap != null && varName in operationConfig.argTypeMap) {
const argTypeDef = operationConfig.argTypeMap[varName];
if (typeof argTypeDef === 'object') {
rootTypeInputTypeDefinition.properties[fieldName].properties[varName] = argTypeDef;
}
else {
rootTypeInputTypeDefinition.properties[fieldName].properties[varName] = {
$ref: argTypeDef,
};
}
}
else if (!rootTypeInputTypeDefinition.properties[fieldName].properties[varName]) {
rootTypeInputTypeDefinition.properties[fieldName].properties[varName] = {
type: 'string',
};
}
}
}
if ('binary' in operationConfig) {
const generatedSchema = {
type: 'string',
format: 'binary',
};
rootTypeInputTypeDefinition.properties[fieldName] = rootTypeInputTypeDefinition.properties[fieldName] || {
title: `${rootTypeInputPropertyName}_${fieldName}`,
type: 'object',
properties: {},
};
rootTypeInputTypeDefinition.properties[fieldName].properties.input = generatedSchema;
}
else if ('requestSchema' in operationConfig && operationConfig.requestSchema) {
rootTypeInputTypeDefinition.properties[fieldName] = rootTypeInputTypeDefinition.properties[fieldName] || {
title: `${rootTypeInputPropertyName}_${fieldName}`,
type: 'object',
properties: {},
};
rootTypeInputTypeDefinition.properties[fieldName].properties.input =
typeof operationConfig.requestSchema === 'string'
? {
$ref: operationConfig.requestSchema,
title: operationConfig.requestTypeName,
}
: operationConfig.requestSchema;
if (operationConfig.requestSample) {
rootTypeInputTypeDefinition.properties[fieldName].properties.input.examples = rootTypeInputTypeDefinition
.properties[fieldName].properties.input.examples || [operationConfig.requestSample];
}
}
else if ('requestSample' in operationConfig) {
const sample = typeof operationConfig.requestSample === 'object'
? operationConfig.requestSample
: await readFileOrUrl(operationConfig.requestSample, {
cwd,
headers: schemaHeaders,
fetch: fetchFn,
logger,
importFn: defaultImportFn,
}).catch((e) => {
throw new Error(`${operationConfig.field}.requestSample: ${operationConfig.requestSample}; ${e.message}`);
});
const generatedSchema = toJsonSchema(sample, {
required: false,
objects: {
additionalProperties: false,
},
strings: {
detectFormat: true,
},
arrays: {
mode: 'first',
},
});
generatedSchema.title = operationConfig.requestTypeName;
generatedSchema.examples = [sample];
rootTypeInputTypeDefinition.properties[fieldName] = rootTypeInputTypeDefinition.properties[fieldName] || {
title: `${rootTypeInputPropertyName}_${fieldName}`,
type: 'object',
properties: {},
};
rootTypeInputTypeDefinition.properties[fieldName].properties.input = generatedSchema;
}
}
return finalJsonSchema;
}
async function getDereferencedJSONSchemaFromOperations({ operations, cwd = process$1.cwd(), logger, fetchFn, schemaHeaders, ignoreErrorResponses, baseUrl, operationHeaders, queryParams, }) {
const referencedJSONSchema = await getReferencedJSONSchemaFromOperations({
operations,
cwd,
schemaHeaders,
ignoreErrorResponses,
fetchFn,
baseUrl,
operationHeaders,
queryParams,
});
logger.debug(`Dereferencing JSON Schema to resolve all $refs`);
const schemaHeadersFactory = getInterpolatedHeadersFactory(schemaHeaders);
const fullyDeferencedSchema = await dereferenceObject(referencedJSONSchema, {
cwd,
fetchFn,
logger: logger.child('dereferenceObject'),
headers: schemaHeadersFactory({ env: process$1.env }),
});
logger.debug(`Healing JSON Schema`);
const healedSchema = await healJSONSchema(fullyDeferencedSchema, {
logger: logger.child('healJSONSchema'),
});
return healedSchema;
}
function resolveDataByUnionInputType(data, type, schemaComposer) {
var _a;
if (data) {
if (isListType(type)) {
return asArray(data).map(elem => resolveDataByUnionInputType(elem, type.ofType, schemaComposer));
}
if (isNonNullType(type)) {
return resolveDataByUnionInputType(data, type.ofType, schemaComposer);
}
if (isInputObjectType(type)) {
const fieldMap = type.getFields();
const isOneOf = schemaComposer.getAnyTC(type).getDirectiveByName('oneOf');
data = asArray(data)[0];
for (const propertyName in data) {
const fieldName = sanitizeNameForGraphQL(propertyName);
const field = fieldMap[fieldName];
if (field) {
if (isOneOf) {
const resolvedData = resolveDataByUnionInputType(data[fieldName], field.type, schemaComposer);
return resolvedData;
}
const fieldData = data[fieldName];
data[fieldName] = undefined;
const realFieldName = ((_a = field.extensions) === null || _a === void 0 ? void 0 : _a.propertyName) || fieldName;
data[realFieldName] = resolveDataByUnionInputType(fieldData, field.type, schemaComposer);
}
}
}
}
return data;
}
const defaultQsOptions = {
indices: false,
};
const isListTypeOrNonNullListType = memoize1(function isListTypeOrNonNullListType(type) {
if (isNonNullType(type)) {
return isListType(type.ofType);
}
return isListType(type);
});
function createError(message, extensions) {
return new GraphQLError(message, undefined, undefined, undefined, undefined, undefined, extensions);
}
function linkResolver(linkObjArgs, actualResolver, root, args, context, info) {
for (const argKey in linkObjArgs) {
const argInterpolation = linkObjArgs[argKey];
const actualValue = typeof argInterpolation === 'string'
? stringInterpolator.parse(argInterpolation, {
root,
args,
context,
info,
env: process$1.env,
})
: argInterpolation;
lodashSet(args, argKey, actualValue);
}
return actualResolver(root, args, context, info);
}
const responseMetadataType = new GraphQLObjectType({
name: 'ResponseMetadata',
fields: {
url: { type: GraphQLString },
method: { type: GraphQLString },
status: { type: GraphQLInt },
statusText: { type: GraphQLString },
headers: { type: GraphQLJSON },
body: { type: GraphQLJSON },
},
});
async function addExecutionLogicToComposer(name, { schemaComposer, fetch: globalFetch, logger, operations, operationHeaders, baseUrl, pubsub: globalPubsub, queryParams, queryStringOptions = {}, }) {
logger.debug(`Attaching execution logic to the schema`);
queryStringOptions = { ...defaultQsOptions, ...queryStringOptions };
const linkResolverMapByField = new Map();
for (const operationConfig of operations) {
const { httpMethod, rootTypeName, fieldName } = getOperationMetadata(operationConfig);
const operationLogger = logger.child(`${rootTypeName}.${fieldName}`);
const rootTypeComposer = schemaComposer[rootTypeName];
const field = rootTypeComposer.getField(fieldName);
if (isPubSubOperationConfig(operationConfig)) {
field.description = operationConfig.description || `PubSub Topic: ${operationConfig.pubsubTopic}`;
field.subscribe = (root, args, context, info) => {
const pubsub = (context === null || context === void 0 ? void 0 : context.pubsub) || globalPubsub;
if (!pubsub) {
return new GraphQLError(`You should have PubSub defined in either the config or the context!`);
}
const interpolationData = { root, args, context, info, env: process$1.env };
let pubsubTopic = stringInterpolator.parse(operationConfig.pubsubTopic, interpolationData);
if (pubsubTopic.startsWith('webhook:')) {
const [, expectedMethod, expectedUrl] = pubsubTopic.split(':');
const expectedPath = new URL(expectedUrl, 'http://localhost').pathname;
pubsubTopic = `webhook:${expectedMethod}:${expectedPath}`;
}
operationLogger.debug(`=> Subscribing to pubSubTopic: ${pubsubTopic}`);
return pubsub.asyncIterator(pubsubTopic);
};
field.resolve = root => {
operationLogger.debug('Received ', root, ' from ', operationConfig.pubsubTopic);
return root;
};
}
else if (operationConfig.path) {
if (process$1.env.DEBUG === '1' || process$1.env.DEBUG === 'fieldDetails') {
field.description = `
>**Method**: \`${operationConfig.method}\`
>**Base URL**: \`${baseUrl}\`
>**Path**: \`${operationConfig.path}\`
${operationConfig.description || ''}
`;
}
else {
field.description = operationConfig.description;
}
field.resolve = async (root, args, context, info) => {
var _a, _b, _c, _d, _e;
operationLogger.debug(`=> Resolving`);
const interpolationData = { root, args, context, env: process$1.env };
const interpolatedBaseUrl = stringInterpolator.parse(baseUrl, interpolationData);
const interpolatedPath = stringInterpolator.parse(operationConfig.path, interpolationData);
let fullPath = urlJoin(interpolatedBaseUrl, interpolatedPath);
const operationHeadersObj = typeof operationHeaders === 'function'
? await operationHeaders(interpolationData, operationConfig)
: operationHeaders;
const headers = {};
for (const headerName in operationHeadersObj) {
const nonInterpolatedValue = operationHeadersObj[headerName];
const interpolatedValue = stringInterpolator.parse(nonInterpolatedValue, interpolationData);
if (interpolatedValue) {
headers[headerName.toLowerCase()] = interpolatedValue;
}
}
if (operationConfig === null || operationConfig === void 0 ? void 0 : operationConfig.headers) {
for (const headerName in operationConfig.headers) {
const nonInterpolatedValue = operationConfig.headers[headerName];
const interpolatedValue = stringInterpolator.parse(nonInterpolatedValue, interpolationData);
if (interpolatedValue) {
headers[headerName.toLowerCase()] = interpolatedValue;
}
}
}
const requestInit = {
method: httpMethod,
headers,
};
// Handle binary data
if ('binary' in operationConfig) {
const binaryUpload = await args.input;
if (isFileUpload(binaryUpload)) {
const readable = binaryUpload.createReadStream();
const chunks = [];
for await (const chunk of readable) {
for (const byte of chunk) {
chunks.push(byte);
}
}
requestInit.body = new Uint8Array(chunks);
const [, contentType] = Object.entries(headers).find(([key]) => key.toLowerCase() === 'content-type') || [];
if (!contentType) {
headers['content-type'] = binaryUpload.mimetype;
}
}
requestInit.body = binaryUpload;
}
else {
if (operationConfig.requestBaseBody != null) {
args.input = args.input || {};
for (const key in operationConfig.requestBaseBody) {
const configValue = operationConfig.requestBaseBody[key];
if (typeof configValue === 'string') {
const value = stringInterpolator.parse(configValue, interpolationData);
lodashSet(args.input, key, value);
}
else {
args.input[key] = configValue;
}
}
}
// Resolve union input
const input = (args.input = resolveDataByUnionInputType(args.input, (_c = (_b = (_a = field.args) === null || _a === void 0 ? void 0 : _a.input) === null || _b === void 0 ? void 0 : _b.type) === null || _c === void 0 ? void 0 : _c.getType(), schemaComposer));
if (input != null) {
const [, contentType] = Object.entries(headers).find(([key]) => key.toLowerCase() === 'content-type') || [];
if (contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('application/x-www-form-urlencoded')) {
requestInit.body = stringify(input, queryStringOptions);
}
else if (contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('multipart/form-data')) {
delete headers['content-type'];
delete headers['Content-Type'];
const formData = new FormData();
for (const key in input) {
const inputValue = input[key];
if (inputValue != null) {
let formDataValue;
if (typeof inputValue === 'object') {
if (inputValue instanceof File) {
formDataValue = inputValue;
}
else if (inputValue.name && inputValue instanceof Blob) {
formDataValue = new File([inputValue], inputValue.name, { type: inputValue.type });
}
else if (inputValue.arrayBuffer) {
const arrayBuffer = await inputValue.arrayBuffer();
if (inputValue.name) {
formDataValue = new File([arrayBuffer], inputValue.name, { type: inputValue.type });
}
else {
formDataValue = new Blob([arrayBuffer], { type: inputValue.type });
}
}
else {
formDataValue = JSON.stringify(inputValue);
}
}
else {
formDataValue = inputValue.toString();
}
formData.append(key, formDataValue);
}
}
requestInit.body = formData;
}
else {
requestInit.body = typeof input === 'object' ? JSON.stringify(input) : input;
}
}
}
if (queryParams) {
for (const queryParamName in queryParams) {
if (args != null &&
operationConfig.queryParamArgMap != null &&
queryParamName in operationConfig.queryParamArgMap &&
operationConfig.queryParamArgMap[queryParamName] in args) {
continue;
}
const interpolatedQueryParam = stringInterpolator.parse(queryParams[queryParamName].toString(), interpolationData);
const queryParamsString = stringify({
[queryParamName]: interpolatedQueryParam,
}, {
...queryStringOptions,
...(_d = operationConfig.queryStringOptionsByParam) === null || _d === void 0 ? void 0 : _d[queryParamName],
});
fullPath += fullPath.includes('?') ? '&' : '?';
fullPath += queryParamsString;
}
}
if (operationConfig.queryParamArgMap) {
for (const queryParamName in operationConfig.queryParamArgMap) {
const argName = operationConfig.queryParamArgMap[queryParamName];
let argValue = args[argName];
if (argValue != null) {
// Somehow it doesn't serialize URLs so we need to do it manually.
if (argValue instanceof URL) {
argValue = argValue.toString();
}
const opts = {
...queryStringOptions,
...(_e = operationConfig.queryStringOptionsByParam) === null || _e === void 0 ? void 0 : _e[queryParamName],
};
let queryParamObj = argValue;
if (Array.isArray(argValue) || !opts.destructObject) {
queryParamObj = {
[queryParamName]: argValue,
};
}
const queryParamsString = stringify(queryParamObj, opts);
fullPath += fullPath.includes('?') ? '&' : '?';
fullPath += queryParamsString;
}
}
}
operationLogger.debug(`=> Fetching `, fullPath, `=>`, requestInit);
const fetch = (context === null || context === void 0 ? void 0 : context.fetch) || globalFetch;
if (!fetch) {
return createError(`You should have fetch defined in either the config or the context!`, {
url: fullPath,
method: httpMethod,
});
}
// Trick to pass `sourceName` to the `fetch` function for tracing
const response = await fetch(fullPath, requestInit, context, {
...info,
sourceName: name,
});
// If return type is a file
if (field.type.getTypeName() === 'File') {
return response.blob();
}
const responseText = await response.text();
operationLogger.debug(`=> Received`, {
headers: response.headers,
text: responseText,
});
let responseJson;
try {
responseJson = JSON.parse(responseText);
}
catch (error) {
const returnNamedGraphQLType = getNamedType(field.type.getType());
// The result might be defined as scalar
if (isScalarType(returnNamedGraphQLType)) {
operationLogger.debug(` => Return type is not a JSON so returning ${responseText}`);
return responseText;
}
else if (response.status === 204) {
responseJson = {};
}
else {
logger.debug(`Unexpected response in ${fieldName};\n\t${responseText}`);
return createError(`Unexpected response`, {
url: fullPath,
method: httpMethod,
responseText,
error,
});
}
}
if (!response.status.toString().startsWith('2')) {
const returnNamedGraphQLType = getNamedType(field.type.getType());
if (!isUnionType(returnNamedGraphQLType)) {
return createError(`HTTP Error: ${response.status}, Could not invoke operation ${operationConfig.method} ${operationConfig.path}`, {
method: httpMethod,
url: fullPath,
statusCode: response.status,
statusText: response.statusText,
responseBody: responseJson,
});
}
}
operationLogger.debug(`Returning `, responseJson);
// Sometimes API returns an array but the return type is not an array
const isListReturnType = isListTypeOrNonNullListType(field.type.getType());
const isArrayResponse = Array.isArray(responseJson);
if (isListReturnType && !isArrayResponse) {
operationLogger.debug(`Response is not array but return type is list. Normalizing the response`);
responseJson = [responseJson];
}
if (!isListReturnType && isArrayResponse) {
operationLogger.debug(`Response is array but return type is not list. Normalizing the response`);
responseJson = responseJson[0];
}
const addResponseMetadata = (obj) => {
if (typeof obj !== 'object') {
return obj;
}
Object.defineProperties(obj, {
$field: {
get() {
return operationConfig.field;
},
},
$url: {
get() {
return fullPath.split('?')[0];
},
},
$method: {
get() {
return httpMethod;
},
},
$statusCode: {
get() {
return response.status;
},
},
$statusText: {
get() {
return response.statusText;
},
},
$headers: {
get() {
return requestInit.headers;
},
},
$request: {
get() {
return new Proxy({}, {
get(_, requestProp) {
switch (requestProp) {
case 'query':
return parse(fullPath.split('?')[1]);
case 'path':
return new Proxy(args, {
get(_, prop) {
var _a;
return args[prop] || ((_a = args.input) === null || _a === void 0 ? void 0 : _a[prop]) || (obj === null || obj === void 0 ? void 0 : obj[prop]);
},
has(_, prop) {
return prop in args || (args.input && prop in args.input) || (obj === null || obj === void 0 ? void 0 : obj[prop]);
},
});
case 'header':
return getHeadersObj(requestInit.headers);
case 'body':
return requestInit.body;
}
},
});
},
},
$response: {
get() {
return new Proxy({}, {
get(_, responseProp) {
switch (responseProp) {
case 'header':
return getHeadersObj(response.headers);
case 'body':
return obj;
case 'query':
return parse(fullPath.split('?')[1]);
case 'path':
return new Proxy(args, {
get(_, prop) {
var _a;
return args[prop] || ((_a = args.input) === null || _a === void 0 ? void 0 : _a[prop]) || (obj === null || obj === void 0 ? void 0 : obj[prop]);
},
has(_, prop) {
return prop in args || (args.input && prop in args.input) || (obj === null || obj === void 0 ? void 0 : obj[prop]);
},
});
}
},
});
},
},
});
return obj;
};
operationLogger.debug(`Adding response metadata to the response object`);
return Array.isArray(responseJson)
? responseJson.map(obj => addResponseMetadata(obj))
: addResponseMetadata(responseJson);
};
const handleLinkMap = (linkMap, typeTC) => {
for (const linkName in linkMap) {
typeTC.addFields({
[linkName]: () => {
const linkObj = linkMap[linkName];
let linkResolverFieldMap = linkResolverMapByField.get(operationConfig.field);
if (!linkResolverFieldMap) {
linkResolverFieldMap = {};
linkResolverMapByField.set(operationConfig.field, linkResolverFieldMap);
}
let targetField;
try {
targetField = schemaComposer.Query.getField(linkObj.fieldName);
}
catch (_a) {
try {
targetField = schemaComposer.Mutation.getField(linkObj.fieldName);
}
catch (_b) { }
}
if (!targetField) {
logger.debug(`Field ${linkObj.fieldName} not found in ${name} for link ${linkName}`);
}
linkResolverFieldMap[linkName] = (root, args, context, info) => linkResolver(linkObj.args, targetField.resolve, root, args, context, info);
return {
...targetField,
args: linkObj.args ? {} : targetField.args,
description: linkObj.description || targetField.description,
// Pick the correct link resolver if there are many link for the same return type used by different operations
resolve: (root, args, context, info) => {
var _a;
const linkResolverFieldMapForCurrentField = (_a = linkResolverMapByField.get(root.$field)) !== null && _a !== void 0 ? _a : linkResolverFieldMap;
return linkResolverFieldMapForCurrentField[linkName](root, args, context, info);
},
};
},
});
}
};
if ('links' in operationConfig) {
const typeTC = schemaComposer.getOTC(field.type.getTypeName());
handleLinkMap(operationConfig.links, typeTC);
}
if ('exposeResponseMetadata' in operationConfig && operationConfig.exposeResponseMetadata) {
const typeTC = schemaComposer.getOTC(field.type.getTypeName());
typeTC.addFields({
_response: {
type: responseMetadataType,
resolve: root => ({
url: root.$url,
headers: root.$response.header,
method: root.$method,
status: root.$statusCode,
statusText: root.$statusText,
body: root.$response.body,
}),
},
});
}
if ('responseByStatusCode' in operationConfig) {
const unionOrSingleTC = schemaComposer.getAnyTC(getNamedType(field.type.getType()));
const types = 'getTypes' in unionOrSingleTC ? unionOrSingleTC.getTypes() : [unionOrSingleTC];
const statusCodeOneOfIndexMap = unionOrSingleTC.getExtension('statusCodeOneOfIndexMap') || {};
for (const statusCode in operationConfig.responseByStatusCode) {
const responseConfig = operationConfig.responseByStatusCode[statusCode];
if (responseConfig.links || responseConfig.exposeResponseMetadata) {
const typeTCThunked = types[statusCodeOneOfIndexMap[statusCode] || 0];
const originalName = typeTCThunked.getTypeName();
let typeTC = schemaComposer.getAnyTC(originalName);
if (!('addFieldArgs' in typeTC)) {
typeTC = schemaComposer.createObjectTC({
name: `${operationConfig.field}_${statusCode}_response`,
fields: {
[originalName]: {
type: typeTC,
resolve: root => root,
},
},
});
// If it is a scalar or enum type, it cannot be a union type, so we can set it directly
types[0] = typeTC;
field.type = typeTC;
}
if (responseConfig.exposeResponseMetadata) {
typeTC.addFields({
_response: {
type: responseMetadataType,
resolve: root => root.$response,
},
});
}
if (responseConfig.links) {
handleLinkMap(responseConfig.links, typeTC);
}
}
}
}
}
}
logger.debug(`Building the executable schema.`);
return schemaComposer;
}
function getValidTypeName({ schemaComposer, isInput, subSchema, }) {
if (!subSchema.title) {
throw new Error('Missing title for schema; ' + inspect(subSchema));
}
const sanitizedName = sanitizeNameForGraphQL(isInput ? subSchema.title + '_Input' : subSchema.title);
if (schemaComposer.has(sanitizedName)) {
let i = 2;
while (schemaComposer.has(sanitizedName + i)) {
i++;
}
return sanitizedName + i;
}
return sanitizedName;
}
function getStringScalarWithMinMaxLength({ schemaComposer, subSchema, }) {
const name = getValidTypeName({
schemaComposer,
isInput: false,
subSchema,
});
function coerceString(value) {
if (value != null) {
const vStr = value.toString();
if (typeof subSchema.minLength !== 'undefined' && vStr.length < subSchema.minLength) {
throw new Error(`${name} cannot be less than ${subSchema.minLength} but given ${vStr}`);
}
if (typeof subSchema.maxLength !== 'undefined' && vStr.length > subSchema.maxLength) {
throw new Error(`${name} cannot be more than ${subSchema.maxLength} but given ${vStr}`);
}
return vStr;
}
}
return schemaComposer.createScalarTC({
name,
description: subSchema.description,
serialize: coerceString,
parseValue: coerceString,
parseLiteral: ast => {
if ('value' in ast) {
return coerceString(ast.value);
}
return null;
},
extensions: {
codegenScalarType: 'string',
},
});
}
const JSONSchemaStringFormats = [
'date',
'hostname',
'regex',
'json-pointer',
'relative-json-pointer',
'uri-reference',
'uri-template',
];
function getJSONSchemaStringFormatScalarMap(ajv) {
const map = new Map();
for (const format of JSONSchemaStringFormats) {
const schema = {
type: 'string',
format,
};
let validate;
try {
validate = ajv.compile(schema);
}
catch (e) {
validate = (value) => ajv.validate(schema, value);
}
const coerceString = (value) => {
if (validate(value)) {
return value;
}
throw new Error(`Expected ${format} but got: ${value}`);
};
const scalar = new GraphQLScalarType({
name: pascalCase(format),
description: `Represents ${format} values`,
serialize: coerceString,
parseValue: coerceString,
parseLiteral: ast => {
if (ast.kind === Kind.STRING) {
return coerceString(ast.value);
}
throw new Error(`Expected string in ${format} format but got: ${ast.value}`);
},
extensions: {
codegenScalarType: 'string',
},
});
map.set(format, scalar);
}
return map;
}
function getTypeResolverFromOutputTCs(ajv, outputTypeComposers, subSchemaAndTypeComposers, statusCodeOneOfIndexMap) {
var _a;
const statusCodeTypeMap = new Map();
for (const statusCode in statusCodeOneOfIndexMap) {
statusCodeTypeMap.set(statusCode.toString(), outputTypeComposers[statusCodeOneOfIndexMap[statusCode]]);
}
const discriminatorField = (_a = subSchemaAndTypeComposers.discriminator) === null || _a === void 0 ? void 0 : _a.propertyName;
return function resolveType(data, context, info) {
if (data.__typename) {
return data.__typename;
}
else if (discriminatorField != null && data[discriminatorField]) {
return data[discriminatorField];
}
if (data.$statusCode && statusCodeOneOfIndexMap) {
const type = statusCodeTypeMap.get(data.$statusCode.toString()) || statusCodeTypeMap.get('default');
if (type) {
if ('getFields' in type) {
return type.getTypeName();
}
else {
return type.getResolveType()(data, context, info, type.getType());
}
}
}
const validationErrors = {};
const dataKeys = typeof data === 'object'
? Object.keys(data)
// Remove metadata fields used to pass data
.filter(property => !property.toString().startsWith('$'))
: null;
const allOutputTypeComposers = outputTypeComposers.flatMap(typeComposer => 'getFields' in typeComposer ? typeComposer : typeComposer.getTypeComposers());
for (const outputTypeComposer of allOutputTypeComposers) {
const typeName = outputTypeComposer.getTypeName();
if (dataKeys != null) {
const typeFields = outputTypeComposer.getFieldNames();
if (dataKeys.length <= typeFields.length &&
dataKeys.every(property => typeFields.includes(property.toString()))) {
return typeName;
}
}
else {
const validateFn = outputTypeComposer.getExtension('validateWithJSONSchema');
if (validateFn) {
const isValid = validateFn(data);
if (isValid) {
return typeName;
}
validationErrors[typeName] = ajv.errors || validateFn.errors;
}
}
}
if (data.$response) {
const error = new GraphQLError(`HTTP Error: ${data.$statusCode}`, undefined, undefined, undefined, undefined, undefined, {
$url: data.$url,
$method: data.$method,
$statusCode: data.$statusCode,
$request: {
query: data.$request.query,
header: data.$request.header,
},
$response: {
header: data.$response.header,
body: data.$response.body,
},
});
return error;
}
const error = new GraphQLError(`Received data doesn't met the union`, null, null, null, null, null, {
validationErrors,
});
return error;
};
}
const ONE_OF_DEFINITION = /* GraphQL */ `
directive @oneOf on INPUT_OBJECT | FIELD_DEFINITION
`;
function getContainerTC(schemaComposer, output) {
const containerTypeName = `${output.getTypeName()}_container`;
return schemaComposer.getOrCreateOTC(containerTypeName, otc => otc.addFields({
[output.getTypeName()]: {
type: output,
resolve: root => root,
},
}));
}
function getUnionTypeComposers({ schemaComposer, ajv, typeComposersList, subSchemaAndTypeComposers, logger, }) {
if (typeComposersList.length === 1) {
return typeComposersList[0];
}
const unionInputFields = {};
const outputTypeComposers = [];
typeComposersList.forEach(typeComposers => {
const { input, output } = typeComposers;
if (isSomeInputTypeComposer(output)) {
outputTypeComposers.push(getContainerTC(schemaComposer, output));
}
else {
outputTypeComposers.push(output);
}
if (input) {
unionInputFields[input.getTypeName()] = {
type: input,
};
}
if (!input) {
logger.debug(`No input type composer found for ${output.getTypeName()}, skipping...`);
}
});
if (Object.keys(unionInputFields).length === 1) {
subSchemaAndTypeComposers.input = Object.values(unionInputFields)[0].type;
}
else {
subSchemaAndTypeComposers.input.addFields(unionInputFields);
if (!schemaComposer.hasDirective('oneOf')) {
schemaComposer.addTypeDefs(ONE_OF_DEFINITION);
}
}
const dedupSet = new Set(outputTypeComposers);
if (dedupSet.size === 1) {
subSchemaAndTypeComposers.output = outputTypeComposers[0];
}
else {
const resolveType = getTypeResolverFromOutputTCs(ajv, outputTypeComposers, subSchemaAndTypeComposers, subSchemaAndTypeComposers.output.getExtension('statusCodeOneOfIndexMap'));
subSchemaAndTypeComposers.output.setResolveType(resolveType);
for (const outputTypeComposer of outputTypeComposers) {
if ('getFields' in outputTypeComposer) {
subSchemaAndTypeComposers.output.addType(outputTypeComposer);
}
else {
for (const possibleType of outputTypeComposer.getTypes()) {
subSchemaAndTypeComposers.output.addType(possibleType);
}
}
}
}
return {
input: subSchemaAndTypeComposers.input,
output: subSchemaAndTypeComposers.output,
nullable: subSchemaAndTypeComposers.nullable,
readOnly: subSchemaAndTypeComposers.readOnly,
writeOnly: subSchemaAndTypeComposers.writeOnly,
};
}
function getGenericJSONScalar({ isInput, subSchema, schemaComposer, validateWithJSONSchema, }) {
function coerceGenericJSONScalar(value) {
if (!validateWithJSONSchema(value)) {
throw new Error(`${util.inspect(value)} is not valid!`);
}
return value;
}
const name = getValidTypeName({
schemaComposer,
isInput,
subSchema,
});
return schemaComposer.createScalarTC({
name,
description: subSchema.description,
serialize: coerceGenericJSONScalar,
parseValue: coerceGenericJSONScalar,
parseLiteral(...args) {
const value = GraphQLJSON.parseLiteral(...args);
return coerceGenericJSONScalar(value);
},
extensions: {
codegenScalarType: 'any',
examples: subSchema.examples,
default: subSchema.default,
},
});
}
const ajvMemoizedCompile = memoize2(function ajvCompile(ajv, jsonSchema) {
const schema = typeof jsonSchema === 'object'
? {
...jsonSchema,
$schema: undefined,
}
: jsonSchema;
try {
return ajv.compile(schema);
}
catch (_a) {
// eslint-disable-next-line no-inner-declarations
function validateFn(value) {
return ajv.validate(schema, value);
}
Object.defineProperty(validateFn, 'errors', {
get() {
return ajv.errors;
},
});
return validateFn;
}
});
function getValidateFnForSchemaPath(ajv, path, schema) {
const subSchema = resolvePath(path, schema);
const fn = function validateFn(data) {
const ajvValidateFn = ajvMemoizedCompile(ajv, subSchema);
return ajvValidateFn(data);
};
Object.defineProperty(fn, 'errors', {
get() {
return ajvMemoizedCompile(ajv, subSchema).errors;
},
});
return fn;
}
/* eslint-disable no-case-declarations */
const isListTC = memoize1(function isListTC(type) {
return type instanceof ListComposer;
});
const GraphQLVoid = new GraphQLScalarType({
name: 'Void',
description: 'Represents empty values',
serialize: () => '',
extensions: {
codegenScalarType: 'void',
},
});
const GraphQLFile = new GraphQLScalarType({
name: 'File',
description: 'The `File` scalar type represents a file upload.',
extensions: {
codegenScalarType: 'File',
},
});
function getComposerFromJSONSchema(schema, logger) {
const schemaComposer = new SchemaComposer();
const ajv = new Ajv({
strict: false,
});
addFormats(ajv);
const formatScalarMap = getJSONSchemaStringFormatScalarMap(ajv);
const rootInputTypeNameComposerMap = {
QueryInput: () => schemaComposer.Query,
MutationInput: () => schemaComposer.Mutation,
SubscriptionInput: () => schemaComposer.Subscription,
};
return visitJSONSchema(schema, {
enter(subSchema, { path, visitedSubschemaResultMap }) {
var _a;
if (typeof subSchema === 'boolean' || subSchema.title === 'Any') {
const typeComposer = schemaComposer.getAnyTC(GraphQLJSON$1);
return subSchema
? {
input: typeComposer,
output: typeComposer,
}
: undefined;
}
const validateWithJSONSchema = getValidateFnForSchemaPath(ajv, path, schema);
if (!subSchema) {
throw new Error(`Something is wrong with ${path}`);
}
if (subSchema.pattern) {
let regexp;
try {
regexp = new RegExp(subSchema.pattern);
let codegenScalarType;
switch (subSchema.type) {
case 'string':
codegenScalarType = 'string';
break;
case 'number':
codegenScalarType = 'number';
break;
case 'integer':
if (subSchema.format === 'int64') {
codegenScalarType = 'bigint';
}
else {
codegenScalarType = 'number';
}
break;
}
const scalarType = new RegularExpression(getValidTypeName({
schemaComposer,
isInput: false,
subSchema,
}), regexp, {
description: subSchema.description,
});
scalarType.extensions = scalarType.extensions || {};
scalarType.extensions.codegenScalarType = codegenScalarType;
const typeComposer = schemaComposer.getAnyTC(scalarType);
return {
input: typeComposer,
output: typeComposer,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
};
}
catch (e) {
logger.debug(`RegExp: ${subSchema.pattern} is not valid`, e);
}
}
if (subSchema.const) {
const scalarTypeName = getValidTypeName({
schemaComposer,
isInput: false,
subSchema,
});
const typeComposer = schemaComposer.createEnumTC({
name: scalarTypeName,
values: {
[sanitizeNameForGraphQL(subSchema.const.toString())]: {
value: subSchema.const,
},
},
extensions: {
codegenScalarType: JSON.stringify(subSchema.const),
examples: [subSchema.const],
default: subSchema.const,
},
});
return {
input: typeComposer,
output: typeComposer,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
};
}
if (subSchema.enum && subSchema.type !== 'boolean') {
const values = {};
for (const value of subSchema.enum) {
let enumKey = sanitizeNameForGraphQL(value.toString());
if (enumKey === 'false' || enumKey === 'true' || enumKey === 'null') {
enumKey = enumKey.toUpperCase();
}
if (typeof enumKey === 'string' && enumKey.length === 0) {
enumKey = '_';
}
values[enumKey] = {
// Falsy values are ignored by GraphQL
// eslint-disable-next-line no-unneeded-ternary
value: value ? value : value === null || value === void 0 ? void 0 : value.toString(),
};
}
const typeComposer = schemaComposer.createEnumTC({
name: getValidTypeName({
schemaComposer,
isInput: false,
subSchema,
}),
values,
description: subSchema.description,
extensions: {
examples: subSchema.examples,
default: subSchema.default,
},
});
return {
input: typeComposer,
output: typeComposer,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
if (Array.isArray(subSchema.type)) {
const validTypes = subSchema.type.filter((typeName) => typeName !== 'null');
if (validTypes.length === 1) {
subSchema.type = validTypes[0];
// continue with the single type
}
else if (validTypes.length === 0) {
const typeComposer = schemaComposer.getAnyTC(GraphQLVoid);
return {
input: typeComposer,
output: typeComposer,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
else {
const typeComposer = getGenericJSONScalar({
isInput: true,
subSchema,
schemaComposer,
validateWithJSONSchema,
});
return {
input: typeComposer,
output: typeComposer,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
}
if (subSchema.format) {
switch (subSchema.format) {
case 'byte': {
const typeComposer = schemaComposer.getAnyTC(GraphQLByte);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
default: subSchema.default,
};
}
case 'binary': {
const typeComposer = schemaComposer.getAnyTC(GraphQLFile);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
default: subSchema.default,
};
}
case 'date-time': {
const typeComposer = schemaComposer.getAnyTC(GraphQLDateTime);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
case 'time': {
const typeComposer = schemaComposer.getAnyTC(GraphQLTime);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
case 'email': {
const typeComposer = schemaComposer.getAnyTC(GraphQLEmailAddress);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
case 'ipv4': {
const typeComposer = schemaComposer.getAnyTC(GraphQLIPv4);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
case 'ipv6': {
const typeComposer = schemaComposer.getAnyTC(GraphQLIPv6);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
case 'uri': {
const typeComposer = schemaComposer.getAnyTC(GraphQLURL);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
case 'uuid': {
const typeComposer = schemaComposer.getAnyTC(GraphQLUUID);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
case 'unix-time': {
const typeComposer = schemaComposer.createScalarTC(GraphQLTimestamp);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
case 'int64': {
const typeComposer = schemaComposer.createScalarTC(GraphQLBigInt);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
case 'int32': {
const typeComposer = schemaComposer.createScalarTC(GraphQLInt);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
case 'decimal':
case 'float': {
const typeComposer = schemaComposer.createScalarTC(GraphQLFloat);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
default: {
const formatScalar = formatScalarMap.get(subSchema.format);
if (formatScalar) {
const typeComposer = schemaComposer.getAnyTC(formatScalar);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
}
}
}
if (subSchema.minimum === 0) {
const typeComposer = schemaComposer.getAnyTC(subSchema.type === 'integer' ? GraphQLNonNegativeInt : GraphQLNonNegativeFloat);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
else if (subSchema.minimum > 0) {
const typeComposer = schemaComposer.getAnyTC(subSchema.type === 'integer' ? GraphQLPositiveInt : GraphQLPositiveFloat);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
if (subSchema.maximum === 0) {
const typeComposer = schemaComposer.getAnyTC(subSchema.type === 'integer' ? GraphQLNonPositiveInt : GraphQLNonPositiveFloat);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
else if (subSchema.maximum < 0) {
const typeComposer = schemaComposer.getAnyTC(subSchema.type === 'integer' ? GraphQLNegativeInt : GraphQLNegativeFloat);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
if (subSchema.maximum > Number.MAX_SAFE_INTEGER || subSchema.minimum < Number.MIN_SAFE_INTEGER) {
const typeComposer = schemaComposer.getAnyTC(GraphQLBigInt);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
switch (subSchema.type) {
case 'boolean': {
const typeComposer = schemaComposer.getAnyTC(GraphQLBoolean);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
case 'null': {
const typeComposer = schemaComposer.getAnyTC(GraphQLVoid);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
case 'integer': {
const typeComposer = schemaComposer.getAnyTC(GraphQLInt);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
case 'number': {
const typeComposer = schemaComposer.getAnyTC(GraphQLFloat);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
case 'string': {
if (subSchema.minLength === 1 && subSchema.maxLength == null) {
const tc = schemaComposer.getAnyTC(GraphQLNonEmptyString);
return {
input: tc,
output: tc,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
if (subSchema.minLength || subSchema.maxLength) {
const scalarType = getStringScalarWithMinMaxLength({
schemaComposer,
subSchema,
});
const typeComposer = schemaComposer.getAnyTC(scalarType);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
const typeComposer = schemaComposer.getAnyTC(GraphQLString);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
case 'array':
if (typeof subSchema.items === 'object' && Object.keys(subSchema.items).length > 0) {
return {
// These are filled after enter
get input() {
const typeComposers = visitedSubschemaResultMap.get(subSchema.items);
return typeComposers.input.getTypePlural();
},
get output() {
const typeComposers = visitedSubschemaResultMap.get(subSchema.items);
return typeComposers.output.getTypePlural();
},
...subSchema,
};
}
if (subSchema.contains) {
// Scalars cannot be in union type
const typeComposer = getGenericJSONScalar({
schemaComposer,
isInput: false,
subSchema,
validateWithJSONSchema,
}).getTypePlural();
return {
input: typeComposer,
output: typeComposer,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
// If it doesn't have any clue
{
// const typeComposer = getGenericJSONScalar({
// schemaComposer,
// isInput: false,
// subSchema,
// validateWithJSONSchema,
// }).getTypePlural();
const typeComposer = schemaComposer.getAnyTC(GraphQLJSON$1).getTypePlural();
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
case 'object': {
switch (subSchema.title) {
case '_schema':
return {
output: schemaComposer,
...subSchema,
};
case 'Query':
return {
output: schemaComposer.Query,
...subSchema,
};
case 'Mutation':
return {
output: schemaComposer.Mutation,
...subSchema,
};
case 'Subscription':
if (path.startsWith('/properties/subscription')) {
return {
output: schemaComposer.Subscription,
...subSchema,
};
}
subSchema.title = 'Subscription_';
break;
}
}
}
if (subSchema.oneOf && !subSchema.properties) {
let statusCodeOneOfIndexMap;
if ((_a = subSchema.$comment) === null || _a === void 0 ? void 0 : _a.startsWith('statusCodeOneOfIndexMap:')) {
const statusCodeOneOfIndexMapStr = subSchema.$comment.replace('statusCodeOneOfIndexMap:', '');
statusCodeOneOfIndexMap = JSON.parse(statusCodeOneOfIndexMapStr);
}
const input = schemaComposer.createInputTC({
name: getValidTypeName({
schemaComposer,
isInput: true,
subSchema,
}),
fields: {},
directives: [
{
name: 'oneOf',
},
],
});
const output = schemaComposer.createUnionTC({
name: getValidTypeName({
schemaComposer,
isInput: false,
subSchema,
}),
description: subSchema.description,
types: [],
extensions: {
statusCodeOneOfIndexMap,
},
});
return {
input,
output,
...subSchema,
};
}
if (subSchema.properties || subSchema.allOf || subSchema.anyOf || subSchema.additionalProperties) {
if (subSchema.title === 'Any') {
const typeComposer = schemaComposer.getAnyTC(GraphQLJSON$1);
return {
input: typeComposer,
output: typeComposer,
description: subSchema.description,
nullable: subSchema.nullable,
readOnly: subSchema.readOnly,
writeOnly: subSchema.writeOnly,
default: subSchema.default,
};
}
const config = {
name: getValidTypeName({
schemaComposer,
isInput: false,
subSchema,
}),
description: subSchema.description,
fields: {},
extensions: {
validateWithJSONSchema,
examples: subSchema.examples,
default: subSchema.default,
},
};
return {
input: schemaComposer.createInputTC({
name: getValidTypeName({
schemaComposer,
isInput: true,
subSchema,
}),
description: subSchema.description,
fields: {},
extensions: {
examples: subSchema.examples,
default: subSchema.default,
},
}),
output: subSchema.discriminator
? schemaComposer.createInterfaceTC({
...config,
resolveType(root) {
return root[subSchema.discriminator];
},
})
: schemaComposer.createObjectTC(config),
...subSchema,
...(subSchema.properties ? { properties: { ...subSchema.properties } } : {}),
...(subSchema.allOf ? { allOf: [...subSchema.allOf] } : {}),
...(subSchema.additionalProperties
? {
additionalProperties: subSchema.additionalProperties === true ? true : { ...subSchema.additionalProperties },
}
: {}),
};
}
return subSchema;
},
leave(subSchemaAndTypeComposers, { path }) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
const validateWithJSONSchema = getValidateFnForSchemaPath(ajv, path, schema);
const subSchemaOnly = {
...subSchemaAndTypeComposers,
input: undefined,
output: undefined,
};
if (subSchemaAndTypeComposers.oneOf && !subSchemaAndTypeComposers.properties) {
const isPlural = subSchemaAndTypeComposers.oneOf.some(({ output }) => 'ofType' in output);
if (isPlural) {
const { input, output } = getUnionTypeComposers({
schemaComposer,
ajv,
typeComposersList: subSchemaAndTypeComposers.oneOf.map(({ input, output }) => ({
input: input.ofType || input,
output: output.ofType || output,
})),
subSchemaAndTypeComposers,
logger,
});
return {
input: input.getTypePlural(),
output: output.getTypePlural(),
nullable: subSchemaAndTypeComposers.nullable,
default: subSchemaAndTypeComposers.default,
readOnly: subSchemaAndTypeComposers.readOnly,
writeOnly: subSchemaAndTypeComposers.writeOnly,
};
}
return getUnionTypeComposers({
schemaComposer,
ajv,
typeComposersList: subSchemaAndTypeComposers.oneOf,
subSchemaAndTypeComposers,
logger,
});
}
const fieldMap = {};
const inputFieldMap = {};
let isList = false;
if (subSchemaAndTypeComposers.allOf) {
let ableToUseGraphQLInputObjectType = true;
for (const maybeTypeComposers of subSchemaAndTypeComposers.allOf) {
let { input: inputTypeComposer, output: outputTypeComposer } = maybeTypeComposers;
if (inputTypeComposer instanceof ListComposer) {
isList = true;
inputTypeComposer = inputTypeComposer.ofType;
}
if (inputTypeComposer instanceof ScalarTypeComposer || inputTypeComposer instanceof EnumTypeComposer) {
ableToUseGraphQLInputObjectType = false;
}
else {
const inputTypeElemFieldMap = inputTypeComposer.getFields();
for (const fieldName in inputTypeElemFieldMap) {
const field = inputTypeElemFieldMap[fieldName];
inputFieldMap[fieldName] = field;
}
}
if (isSomeInputTypeComposer(outputTypeComposer)) {
fieldMap[outputTypeComposer.getTypeName()] = {
type: outputTypeComposer,
resolve: root => root,
};
}
else if (outputTypeComposer instanceof UnionTypeComposer) {
const outputTCElems = outputTypeComposer.getTypes();
for (const outputTCElem of outputTCElems) {
const outputTypeElemFieldMap = outputTCElem.getFields();
for (const fieldName in outputTypeElemFieldMap) {
const field = outputTypeElemFieldMap[fieldName];
fieldMap[fieldName] = field;
}
}
}
else {
if (outputTypeComposer instanceof InterfaceTypeComposer) {
subSchemaAndTypeComposers.output.addInterface(outputTypeComposer);
}
const typeElemFieldMap = outputTypeComposer.getFields();
for (const fieldName in typeElemFieldMap) {
const field = typeElemFieldMap[fieldName];
fieldMap[fieldName] = field;
}
}
}
subSchemaAndTypeComposers.output.addFields(fieldMap);
subSchemaAndTypeComposers.output.setExtensions({
validateWithJSONSchema,
examples: subSchemaAndTypeComposers.examples,
default: subSchemaAndTypeComposers.default,
});
if (ableToUseGraphQLInputObjectType) {
subSchemaAndTypeComposers.input.addFields(inputFieldMap);
subSchemaAndTypeComposers.input.setExtensions({
examples: subSchemaAndTypeComposers.examples,
default: subSchemaAndTypeComposers.default,
});
}
else {
subSchemaAndTypeComposers.input = schemaComposer.getAnyTC(GraphQLJSON$1);
}
}
if (subSchemaAndTypeComposers.anyOf) {
// It should not have `required` because it is `anyOf` not `allOf`
let ableToUseGraphQLInputObjectType = true;
for (const typeComposers of subSchemaAndTypeComposers.anyOf) {
let { input: inputTypeComposer, output: outputTypeComposer } = typeComposers;
if (inputTypeComposer instanceof ListComposer || outputTypeComposer instanceof ListComposer) {
isList = true;
inputTypeComposer = inputTypeComposer.ofType;
outputTypeComposer = outputTypeComposer.ofType;
}
if (inputTypeComposer instanceof ScalarTypeComposer || inputTypeComposer instanceof EnumTypeComposer) {
ableToUseGraphQLInputObjectType = false;
}
else {
const inputTypeElemFieldMap = inputTypeComposer.getFields();
for (const fieldName in inputTypeElemFieldMap) {
// In case of conflict set it to JSON
// TODO: But instead we can convert that field into a oneOf of all possible types
if (inputFieldMap[fieldName]) {
inputFieldMap[fieldName] = {
type: schemaComposer.getAnyTC(GraphQLJSON$1),
};
}
else {
const field = inputTypeElemFieldMap[fieldName];
inputFieldMap[fieldName] = isNonNullType(field.type.getType())
? {
...field,
type: () => field.type.ofType,
}
: field;
}
}
}
if (outputTypeComposer instanceof ScalarTypeComposer) {
const typeName = outputTypeComposer.getTypeName();
// In case of conflict set it to JSON
// TODO: But instead we can convert that field into a union of all possible types
if (fieldMap[typeName] && fieldMap[typeName].type.getTypeName() !== typeName) {
fieldMap[typeName] = {
type: schemaComposer.getAnyTC(GraphQLJSON$1),
};
}
else {
fieldMap[typeName] = {
type: outputTypeComposer,
resolve: root => root,
};
}
}
else {
const typeElemFieldMap = outputTypeComposer.getFields();
for (const fieldName in typeElemFieldMap) {
// In case of conflict set it to JSON
// TODO: But instead we can convert that field into a union of all possible types
const field = typeElemFieldMap[fieldName];
const existingField = fieldMap[fieldName];
fieldMap[fieldName] = {
...field,
type: () => {
const fieldType = field.type.getType();
const namedType = getNamedType(fieldType);
if (existingField) {
const existingFieldType = existingField.type();
const existingNamedType = getNamedType(existingFieldType);
if (existingNamedType.name !== namedType.name) {
return schemaComposer.getAnyTC(GraphQLJSON$1);
}
}
return field.type.getType();
},
};
}
}
}
subSchemaAndTypeComposers.output.addFields(fieldMap);
subSchemaAndTypeComposers.output.setExtensions({
validateWithJSONSchema,
examples: subSchemaAndTypeComposers.examples,
default: subSchemaAndTypeComposers.default,
});
if (ableToUseGraphQLInputObjectType) {
subSchemaAndTypeComposers.input.addFields(inputFieldMap);
subSchemaAndTypeComposers.input.setExtensions({
examples: subSchemaAndTypeComposers.examples,
default: subSchemaAndTypeComposers.default,
});
}
else {
subSchemaAndTypeComposers.input = schemaComposer.getAnyTC(GraphQLJSON$1);
}
}
switch (subSchemaAndTypeComposers.type) {
case 'object':
if (subSchemaAndTypeComposers.properties) {
for (const propertyName in subSchemaAndTypeComposers.properties) {
// TODO: needs to be fixed
if (propertyName === 'additionalProperties') {
continue;
}
const fieldName = sanitizeNameForGraphQL(propertyName);
if (!subSchemaAndTypeComposers.properties[propertyName].writeOnly) {
fieldMap[fieldName] = {
type: () => {
var _a;
const typeComposers = subSchemaAndTypeComposers.properties[propertyName];
let nullable = true;
if ((_a = subSchemaAndTypeComposers.required) === null || _a === void 0 ? void 0 : _a.includes(propertyName)) {
nullable = false;
}
// Nullable has more priority
if (typeComposers.nullable === false) {
nullable = false;
}
if (typeComposers.nullable === true) {
nullable = true;
}
return !nullable ? typeComposers.output.getTypeNonNull() : typeComposers.output;
},
// Make sure you get the right property
resolve: root => {
const typeComposers = subSchemaAndTypeComposers.properties[propertyName];
const actualFieldObj = root[propertyName];
if (actualFieldObj != null) {
const isArray = Array.isArray(actualFieldObj);
const isListType = isListTC(typeComposers.output);
if (isListType && !isArray) {
return [actualFieldObj];
}
else if (!isListTC(typeComposers.output) && isArray) {
return actualFieldObj[0];
}
}
return actualFieldObj;
},
description: subSchemaAndTypeComposers.properties[propertyName].description ||
((_a = subSchemaAndTypeComposers.properties[propertyName].output) === null || _a === void 0 ? void 0 : _a.description),
};
}
if (!subSchemaAndTypeComposers.properties[propertyName].readOnly) {
inputFieldMap[fieldName] = {
type: () => {
var _a, _b;
const typeComposers = subSchemaAndTypeComposers.properties[propertyName];
let nullable = true;
if ((_a = subSchemaAndTypeComposers.required) === null || _a === void 0 ? void 0 : _a.includes(propertyName)) {
nullable = false;
}
// Nullable has more priority
if (typeComposers.nullable === false) {
nullable = false;
}
if (typeComposers.nullable === true) {
nullable = true;
}
return !nullable ? (_b = typeComposers.input) === null || _b === void 0 ? void 0 : _b.getTypeNonNull() : typeComposers.input;
},
// Let execution logic know what is the expected propertyName
extensions: {
propertyName,
},
description: subSchemaAndTypeComposers.properties[propertyName].description ||
((_b = subSchemaAndTypeComposers.properties[propertyName].input) === null || _b === void 0 ? void 0 : _b.description),
defaultValue: ((_c = subSchemaAndTypeComposers.properties[propertyName]) === null || _c === void 0 ? void 0 : _c.default) ||
((_e = (_d = subSchemaAndTypeComposers.properties[propertyName]) === null || _d === void 0 ? void 0 : _d.extensions) === null || _e === void 0 ? void 0 : _e.default) ||
((_g = (_f = subSchemaAndTypeComposers.properties[propertyName]) === null || _f === void 0 ? void 0 : _f.input) === null || _g === void 0 ? void 0 : _g.default),
};
}
}
}
if (subSchemaAndTypeComposers.additionalProperties) {
if (typeof subSchemaAndTypeComposers.additionalProperties === 'object' &&
subSchemaAndTypeComposers.additionalProperties.output instanceof ObjectTypeComposer) {
if (Object.keys(fieldMap).length === 0) {
return subSchemaAndTypeComposers.additionalProperties;
}
else {
const outputTC = subSchemaAndTypeComposers.additionalProperties.output;
const outputTCFieldMap = outputTC.getFields();
for (const fieldName in outputTCFieldMap) {
fieldMap[fieldName] = outputTCFieldMap[fieldName];
}
const inputTC = subSchemaAndTypeComposers.additionalProperties.input;
const inputTCFieldMap = inputTC.getFields();
for (const fieldName in inputTCFieldMap) {
inputFieldMap[fieldName] = inputTCFieldMap[fieldName];
}
}
}
else if (Object.keys(fieldMap).length > 0) {
fieldMap.additionalProperties = {
type: GraphQLJSON$1,
resolve: (root) => root,
};
}
else {
const typeComposer = schemaComposer.getAnyTC(GraphQLJSON$1);
schemaComposer.delete((_j = (_h = subSchemaAndTypeComposers.input) === null || _h === void 0 ? void 0 : _h.getTypeName) === null || _j === void 0 ? void 0 : _j.call(_h));
schemaComposer.delete((_l = (_k = subSchemaAndTypeComposers.output) === null || _k === void 0 ? void 0 : _k.getTypeName) === null || _l === void 0 ? void 0 : _l.call(_k));
return {
input: typeComposer,
output: typeComposer,
description: subSchemaAndTypeComposers.description,
nullable: subSchemaAndTypeComposers.nullable,
default: subSchemaAndTypeComposers.default,
readOnly: subSchemaAndTypeComposers.readOnly,
writeOnly: subSchemaAndTypeComposers.writeOnly,
};
}
}
if (subSchemaAndTypeComposers.title in rootInputTypeNameComposerMap) {
const typeComposer = rootInputTypeNameComposerMap[subSchemaAndTypeComposers.title]();
for (const fieldName in inputFieldMap) {
let inputTC = inputFieldMap[fieldName].type();
if ('ofType' in inputTC) {
inputTC = inputTC.ofType;
}
if (!inputTC.getFields) {
console.log(fieldName);
}
typeComposer.addFieldArgs(fieldName, inputTC.getFields());
}
return {
output: typeComposer,
};
}
let output = subSchemaAndTypeComposers.output;
if (Object.keys(fieldMap).length === 0) {
output = schemaComposer.getAnyTC(GraphQLJSON$1);
}
else if ('addFields' in output) {
output.addFields(fieldMap);
}
let input = subSchemaAndTypeComposers.input;
if (Object.keys(inputFieldMap).length === 0) {
input = schemaComposer.getAnyTC(GraphQLJSON$1);
}
else if (input != null && 'addFields' in input) {
input.addFields(inputFieldMap);
}
if (isList) {
input = input.List;
output = output.List;
}
return {
input,
output,
nullable: subSchemaAndTypeComposers.nullable,
default: subSchemaAndTypeComposers.default,
readOnly: subSchemaAndTypeComposers.readOnly,
writeOnly: subSchemaAndTypeComposers.writeOnly,
};
}
if (subSchemaAndTypeComposers.input || subSchemaAndTypeComposers.output) {
return {
input: subSchemaAndTypeComposers.input,
output: subSchemaAndTypeComposers.output,
description: subSchemaAndTypeComposers.description,
nullable: subSchemaAndTypeComposers.nullable,
default: subSchemaAndTypeComposers.default,
readOnly: subSchemaAndTypeComposers.readOnly,
writeOnly: subSchemaAndTypeComposers.writeOnly,
};
}
else {
logger.debug(`GraphQL Type cannot be created for this JSON Schema definition;`, {
subSchema: subSchemaOnly,
path,
});
const typeComposer = schemaComposer.getAnyTC(GraphQLJSON$1);
return {
input: typeComposer,
output: typeComposer,
description: subSchemaAndTypeComposers.description,
nullable: subSchemaAndTypeComposers.nullable,
readOnly: subSchemaAndTypeComposers.readOnly,
writeOnly: subSchemaAndTypeComposers.writeOnly,
default: subSchemaAndTypeComposers.default,
};
}
},
});
}
async function getGraphQLSchemaFromDereferencedJSONSchema(name, opts) {
const { fullyDeferencedSchema, fetch, logger, operations, operationHeaders, baseUrl, pubsub, queryParams, queryStringOptions, } = opts;
logger.debug(`Generating GraphQL Schema from the bundled JSON Schema`);
const visitorResult = await getComposerFromJSONSchema(fullyDeferencedSchema, logger.child('getComposerFromJSONSchema'));
const schemaComposerWithoutExecutionLogic = visitorResult.output;
if (!(schemaComposerWithoutExecutionLogic instanceof SchemaComposer)) {
throw new Error('The visitor result should be a SchemaComposer instance.');
}
// graphql-compose doesn't add @defer and @stream to the schema
for (const directive of specifiedDirectives) {
schemaComposerWithoutExecutionLogic.addDirective(directive);
}
const schemaComposerWithExecutionLogic = await addExecutionLogicToComposer(name, {
schemaComposer: schemaComposerWithoutExecutionLogic,
fetch,
logger,
operations,
operationHeaders,
baseUrl,
pubsub,
queryParams,
queryStringOptions,
});
if (schemaComposerWithExecutionLogic.Query.getFieldNames().length === 0) {
schemaComposerWithExecutionLogic.Query.addFields({
dummy: {
type: 'String',
resolve: () => 'dummy',
},
});
}
return schemaComposerWithExecutionLogic.buildSchema();
}
async function loadGraphQLSchemaFromJSONSchemas(name, options) {
const logger = options.logger || new DefaultLogger(name);
const operations = options.operations;
const cwd = options.cwd || process.cwd();
const fullyDeferencedSchema = await getDereferencedJSONSchemaFromOperations({
operations,
operationHeaders: typeof options.operationHeaders === 'object' ? options.operationHeaders : {},
queryParams: options.queryParams,
baseUrl: options.baseUrl,
cwd,
logger,
fetchFn: options.fetch,
schemaHeaders: options.schemaHeaders,
ignoreErrorResponses: options.ignoreErrorResponses,
});
const graphqlSchema = await getGraphQLSchemaFromDereferencedJSONSchema(name, {
fullyDeferencedSchema,
fetch: options.fetch,
logger,
operations,
operationHeaders: options.operationHeaders,
baseUrl: options.baseUrl,
pubsub: options.pubsub,
queryParams: options.queryParams,
queryStringOptions: options.queryStringOptions,
});
return graphqlSchema;
}
async function createBundle(name, { baseUrl, operations, schemaHeaders, operationHeaders, queryParams, cwd = process.cwd(), fetch: fetch$1 = fetch, logger = new DefaultLogger(name), ignoreErrorResponses = false, }) {
logger.debug(`Creating the dereferenced schema from operations config`);
const dereferencedSchema = await getDereferencedJSONSchemaFromOperations({
operations,
cwd,
logger,
fetchFn: fetch$1,
schemaHeaders,
ignoreErrorResponses,
baseUrl,
operationHeaders,
queryParams,
});
logger.debug(`Creating references from dereferenced schema`);
const referencedSchema = await referenceJSONSchema(dereferencedSchema);
logger.debug(`Bundle generation finished`);
return {
name,
baseUrl,
operations,
operationHeaders: typeof operationHeaders === 'object' ? operationHeaders : {},
referencedSchema,
};
}
/**
* Generates a local GraphQLSchema instance from
* previously generated JSON Schema bundle
*/
async function getGraphQLSchemaFromBundle({ name, baseUrl: bundledBaseUrl, operations, operationHeaders: bundledOperationHeaders = {}, referencedSchema, }, { cwd = process.cwd(), fetch: fetch$1 = fetch, pubsub, logger = new DefaultLogger(name), baseUrl: overwrittenBaseUrl, operationHeaders: additionalOperationHeaders = {}, queryParams, queryStringOptions, } = {}) {
logger.info(`Dereferencing the bundle`);
const fullyDeferencedSchema = await dereferenceObject(referencedSchema, {
cwd,
fetchFn: fetch$1,
logger,
});
let operationHeaders = {};
if (typeof additionalOperationHeaders === 'function') {
operationHeaders = async (resolverData, operationConfig) => {
const result = await additionalOperationHeaders(resolverData, operationConfig);
return {
...bundledOperationHeaders,
...result,
};
};
}
else {
operationHeaders = {
...bundledOperationHeaders,
...additionalOperationHeaders,
};
}
logger.info(`Creating the GraphQL Schema from dereferenced schema`);
return getGraphQLSchemaFromDereferencedJSONSchema(name, {
fullyDeferencedSchema,
fetch: fetch$1,
pubsub,
logger,
baseUrl: overwrittenBaseUrl || bundledBaseUrl,
operations,
operationHeaders,
queryParams,
queryStringOptions,
});
}
export default loadGraphQLSchemaFromJSONSchemas;
export { createBundle, getComposerFromJSONSchema, getDereferencedJSONSchemaFromOperations, getGraphQLSchemaFromBundle, getGraphQLSchemaFromDereferencedJSONSchema, getReferencedJSONSchemaFromOperations, loadGraphQLSchemaFromJSONSchemas };