Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

graphql-2-json-schema

Package Overview
Dependencies
Maintainers
1
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

graphql-2-json-schema - npm Package Compare versions

Comparing version 0.3.1-0 to 0.3.1

2

CHANGELOG.md

@@ -5,2 +5,4 @@ # Changelog

### [0.3.1](https://github.com/wittydeveloper/graphql-to-json-schema/compare/v0.3.1-0...v0.3.1) (2021-01-21)
### [0.3.1-0](https://github.com/wittydeveloper/graphql-to-json-schema/compare/v0.3.0...v0.3.1-0) (2021-01-19)

@@ -7,0 +9,0 @@

@@ -13,2 +13,3 @@ "use strict";

if (rootMutationType) {
;
introspection.__schema.types.Mutation = rootMutationType;

@@ -21,2 +22,3 @@ introspection.__schema.types.Mutation.name = 'Mutation';

if (rootQueryType) {
;
introspection.__schema.types.Query = rootQueryType;

@@ -26,3 +28,6 @@ introspection.__schema.types.Query.name = 'Query';

}
var _b = lodash_1.partition(introspection.__schema.types, function (type) { return typeGuards_1.isIntrospectionObjectType(type) && lodash_1.includes(['Query', 'Mutation'], type.name); }), properties = _b[0], definitions = _b[1];
var _b = lodash_1.partition(introspection.__schema.types, function (type) {
return typeGuards_1.isIntrospectionObjectType(type) &&
lodash_1.includes(['Query', 'Mutation'], type.name);
}), properties = _b[0], definitions = _b[1];
return {

@@ -29,0 +34,0 @@ $schema: 'http://json-schema.org/draft-06/schema#',

56

dist/lib/reducer.js

@@ -7,18 +7,20 @@ "use strict";

var typesMapping_1 = require("./typesMapping");
var getRequiredFields = function (fields) { return lodash_1.map(lodash_1.filter(fields, function (f) {
return typeGuards_1.isIntrospectionListTypeRef(f.type) ?
typeGuards_1.isNonNullIntrospectionType(f.type.ofType) :
typeGuards_1.isNonNullIntrospectionType(f.type);
}), function (f) { return f.name; }); };
var getRequiredFields = function (fields) {
return lodash_1.map(lodash_1.filter(fields, function (f) {
return typeGuards_1.isIntrospectionListTypeRef(f.type)
? typeGuards_1.isNonNullIntrospectionType(f.type.ofType)
: typeGuards_1.isNonNullIntrospectionType(f.type);
}), function (f) { return f.name; });
};
exports.getRequiredFields = getRequiredFields;
var propertiesIntrospectionFieldReducer = function (acc, curr) {
if (typeGuards_1.isIntrospectionField(curr)) {
var returnType = typeGuards_1.isNonNullIntrospectionType(curr.type) ?
typesMapping_1.graphqlToJSONType(curr.type.ofType) :
typesMapping_1.graphqlToJSONType(curr.type);
var returnType = typeGuards_1.isNonNullIntrospectionType(curr.type)
? typesMapping_1.graphqlToJSONType(curr.type.ofType)
: typesMapping_1.graphqlToJSONType(curr.type);
acc[curr.name] = {
type: 'object',
properties: {
'return': returnType,
'arguments': {
"return": returnType,
arguments: {
type: 'object',

@@ -33,5 +35,5 @@ properties: lodash_1.reduce(curr.args, exports.propertiesIntrospectionFieldReducer, {}),

else if (typeGuards_1.isIntrospectionInputValue(curr)) {
var returnType = typeGuards_1.isNonNullIntrospectionType(curr.type) ?
typesMapping_1.graphqlToJSONType(curr.type.ofType) :
typesMapping_1.graphqlToJSONType(curr.type);
var returnType = typeGuards_1.isNonNullIntrospectionType(curr.type)
? typesMapping_1.graphqlToJSONType(curr.type.ofType)
: typesMapping_1.graphqlToJSONType(curr.type);
acc[curr.name] = returnType;

@@ -48,11 +50,11 @@ if (curr.defaultValue) {

if (typeGuards_1.isIntrospectionField(curr)) {
var returnType = typeGuards_1.isNonNullIntrospectionType(curr.type) ?
typesMapping_1.graphqlToJSONType(curr.type.ofType) :
typesMapping_1.graphqlToJSONType(curr.type);
var returnType = typeGuards_1.isNonNullIntrospectionType(curr.type)
? typesMapping_1.graphqlToJSONType(curr.type.ofType)
: typesMapping_1.graphqlToJSONType(curr.type);
acc[curr.name] = returnType;
}
else if (typeGuards_1.isIntrospectionInputValue(curr)) {
var returnType = typeGuards_1.isNonNullIntrospectionType(curr.type) ?
typesMapping_1.graphqlToJSONType(curr.type.ofType) :
typesMapping_1.graphqlToJSONType(curr.type);
var returnType = typeGuards_1.isNonNullIntrospectionType(curr.type)
? typesMapping_1.graphqlToJSONType(curr.type.ofType)
: typesMapping_1.graphqlToJSONType(curr.type);
acc[curr.name] = returnType;

@@ -68,11 +70,11 @@ if (curr.defaultValue) {

var resolveDefaultValue = function (curr) {
return typeGuards_1.isIntrospectionEnumType(curr.type) ?
curr.defaultValue :
JSON.parse(curr.defaultValue);
return typeGuards_1.isIntrospectionEnumType(curr.type)
? curr.defaultValue
: JSON.parse(curr.defaultValue);
};
exports.resolveDefaultValue = resolveDefaultValue;
var introspectionTypeReducer = function (type) { return function (acc, curr) {
var fieldReducer = type === 'definitions' ?
exports.definitionsIntrospectionFieldReducer :
exports.propertiesIntrospectionFieldReducer;
var fieldReducer = type === 'definitions'
? exports.definitionsIntrospectionFieldReducer
: exports.propertiesIntrospectionFieldReducer;
if (typeGuards_1.isIntrospectionObjectType(curr)) {

@@ -97,5 +99,3 @@ acc[curr.name] = {

return {
"enum": [
item.name,
],
"enum": [item.name],
title: item.description || item.name,

@@ -102,0 +102,0 @@ description: item.description || undefined

@@ -5,32 +5,33 @@ "use strict";

var lodash_1 = require("lodash");
var isIntrospectionField = function (type) {
return lodash_1.has(type, 'args');
};
var isIntrospectionField = function (type) { return lodash_1.has(type, 'args'); };
exports.isIntrospectionField = isIntrospectionField;
var isIntrospectionInputValue = function (type) {
return lodash_1.has(type, 'defaultValue');
};
var isIntrospectionInputValue = function (type) { return lodash_1.has(type, 'defaultValue'); };
exports.isIntrospectionInputValue = isIntrospectionInputValue;
var isIntrospectionListTypeRef = function (type) { return (type.kind === 'LIST'); };
var isIntrospectionListTypeRef = function (type) { return type.kind === 'LIST'; };
exports.isIntrospectionListTypeRef = isIntrospectionListTypeRef;
var isIntrospectionObjectType = function (type) { return (type.kind === 'OBJECT'); };
var isIntrospectionObjectType = function (type) { return type.kind === 'OBJECT'; };
exports.isIntrospectionObjectType = isIntrospectionObjectType;
var isIntrospectionInputObjectType = function (type) { return (type.kind === 'INPUT_OBJECT'); };
var isIntrospectionInputObjectType = function (type) { return type.kind === 'INPUT_OBJECT'; };
exports.isIntrospectionInputObjectType = isIntrospectionInputObjectType;
var isIntrospectionEnumType = function (type) { return (type.kind === 'ENUM'); };
var isIntrospectionEnumType = function (type) { return type.kind === 'ENUM'; };
exports.isIntrospectionEnumType = isIntrospectionEnumType;
var isNonNullIntrospectionType = function (type) { return (type.kind === 'NON_NULL'); };
var isNonNullIntrospectionType = function (type) { return type.kind === 'NON_NULL'; };
exports.isNonNullIntrospectionType = isNonNullIntrospectionType;
var isIntrospectionScalarType = function (type) { return (type.kind === 'SCALAR'); };
var isIntrospectionScalarType = function (type) { return type.kind === 'SCALAR'; };
exports.isIntrospectionScalarType = isIntrospectionScalarType;
var isIntrospectionDefaultScalarType = function (type) { return (type.kind === 'SCALAR' && lodash_1.includes(['Boolean', 'String', 'Int', 'Float'], type.name)); };
var isIntrospectionDefaultScalarType = function (type) {
return type.kind === 'SCALAR' &&
lodash_1.includes(['Boolean', 'String', 'Int', 'Float'], type.name);
};
exports.isIntrospectionDefaultScalarType = isIntrospectionDefaultScalarType;
var filterDefinitionsTypes = function (types, opts) {
var ignoreInternals = opts && opts.ignoreInternals;
return lodash_1.filter(types, function (type) { return ((exports.isIntrospectionObjectType(type) && !!type.fields) ||
(exports.isIntrospectionInputObjectType(type) && !!type.inputFields) ||
(exports.isIntrospectionEnumType(type) && !!type.enumValues) ||
(exports.isIntrospectionScalarType(type) && !!type.name)) &&
(!ignoreInternals || (ignoreInternals && !lodash_1.startsWith(type.name, '__'))); });
return lodash_1.filter(types, function (type) {
return ((exports.isIntrospectionObjectType(type) && !!type.fields) ||
(exports.isIntrospectionInputObjectType(type) && !!type.inputFields) ||
(exports.isIntrospectionEnumType(type) && !!type.enumValues) ||
(exports.isIntrospectionScalarType(type) && !!type.name)) &&
(!ignoreInternals || (ignoreInternals && !lodash_1.startsWith(type.name, '__')));
});
};
exports.filterDefinitionsTypes = filterDefinitionsTypes;

@@ -7,6 +7,6 @@ "use strict";

exports.typesMapping = {
'Boolean': 'boolean',
'String': 'string',
'Int': 'number',
'Float': 'number'
Boolean: 'boolean',
String: 'string',
Int: 'number',
Float: 'number'
};

@@ -25,11 +25,10 @@ var graphqlToJSONType = function (k) {

var name_1 = k.name;
return lodash_1.includes(['OBJECT', 'INPUT_OBJECT', 'ENUM', 'SCALAR'], k.kind) ?
lodash_1.includes(['OBJECT', 'INPUT_OBJECT', 'ENUM'], k.kind) ?
{ $ref: "#/definitions/" + name_1 } :
{ $ref: "#/definitions/" + name_1,
type: exports.typesMapping[name_1]
} :
{ type: exports.typesMapping[name_1] };
return lodash_1.includes(['OBJECT', 'INPUT_OBJECT', 'ENUM', 'SCALAR'], k.kind)
? lodash_1.includes(['OBJECT', 'INPUT_OBJECT', 'ENUM'], k.kind)
? { $ref: "#/definitions/" + name_1 }
:
{ $ref: "#/definitions/" + name_1, type: exports.typesMapping[name_1] }
: { type: exports.typesMapping[name_1] };
}
};
exports.graphqlToJSONType = graphqlToJSONType;

@@ -26,3 +26,3 @@ "use strict";

properties: {
id: { type: 'string', description: "todo identifier" },
id: { type: 'string', description: 'todo identifier' },
isCompleted: { type: 'boolean', "default": false }

@@ -96,7 +96,7 @@ },

definitions: {
'Todo': {
Todo: {
type: 'object',
description: "A ToDo Object",
description: 'A ToDo Object',
properties: {
id: { type: 'string', description: "A unique identifier" },
id: { type: 'string', description: 'A unique identifier' },
name: { type: 'string' },

@@ -106,3 +106,3 @@ completed: { type: 'boolean' },

colors: {
description: "A list containing colors that cannot contain nulls",
description: 'A list containing colors that cannot contain nulls',
type: 'array',

@@ -114,3 +114,3 @@ items: { $ref: '#/definitions/Color' }

},
'Color': {
Color: {
type: 'string',

@@ -127,6 +127,6 @@ anyOf: [

description: 'Green color'
}
},
]
},
'TodoInputType': {
TodoInputType: {
type: 'object',

@@ -133,0 +133,0 @@ description: 'A type that describes ToDoInputType. Its description might not\nfit within the bounds of 80 width and so you want MULTILINE',

@@ -1,2 +0,2 @@

export * from './lib/fromIntrospectionQuery';
export * from './lib/fromIntrospectionQuery'
// export * from './fromGraphQLSchema';

@@ -1,7 +0,7 @@

import { GraphQLSchema } from 'graphql';
import { JSONSchema6 } from 'json-schema';
import { GraphQLSchema } from 'graphql'
import { JSONSchema6 } from 'json-schema'
export const fromIntrospectionQuery = (schema: GraphQLSchema): JSONSchema6 => {
// TODO: implement.
return {};
};
// TODO: implement.
return {}
}

@@ -1,58 +0,68 @@

import { IntrospectionQuery, IntrospectionType } from 'graphql';
import { JSONSchema6 } from 'json-schema';
import { includes, partition, reduce } from 'lodash';
import { introspectionTypeReducer, JSONSchema6Acc } from './reducer';
import { filterDefinitionsTypes, isIntrospectionObjectType } from './typeGuards';
import { IntrospectionQuery, IntrospectionType } from 'graphql'
import { JSONSchema6 } from 'json-schema'
import { includes, partition, reduce } from 'lodash'
import { introspectionTypeReducer, JSONSchema6Acc } from './reducer'
import { filterDefinitionsTypes, isIntrospectionObjectType } from './typeGuards'
// FIXME: finish this type
export interface GraphQLJSONSchema6 extends JSONSchema6 {
properties: {
Query: JSONSchema6Acc;
Mutation: JSONSchema6Acc;
};
definitions: JSONSchema6Acc;
properties: {
Query: JSONSchema6Acc
Mutation: JSONSchema6Acc
}
definitions: JSONSchema6Acc
}
export interface FromIntrospectionQueryOptions {
ignoreInternals?: boolean; // true by default
ignoreInternals?: boolean // true by default
}
export const fromIntrospectionQuery = (
introspection: IntrospectionQuery,
opts?: FromIntrospectionQueryOptions
introspection: IntrospectionQuery,
opts?: FromIntrospectionQueryOptions
): JSONSchema6 => {
const options = opts || { ignoreInternals: true };
const { queryType, mutationType } = introspection.__schema;
const options = opts || { ignoreInternals: true }
const { queryType, mutationType } = introspection.__schema
if (mutationType) {
const rootMutationType = (introspection.__schema.types as any).find( (t: any) => t.name == mutationType.name);
if (rootMutationType) {
(introspection.__schema.types as any).Mutation = rootMutationType;
(introspection.__schema.types as any).Mutation.name = 'Mutation';
}
if (mutationType) {
const rootMutationType = (introspection.__schema.types as any).find(
(t: any) => t.name == mutationType.name
)
if (rootMutationType) {
;(introspection.__schema.types as any).Mutation = rootMutationType
;(introspection.__schema.types as any).Mutation.name = 'Mutation'
}
}
if (queryType) {
const rootQueryType = (introspection.__schema.types as any).find( (t: any) => t.name == queryType.name);
if (rootQueryType) {
(introspection.__schema.types as any).Query = rootQueryType;
(introspection.__schema.types as any).Query.name = 'Query';
}
if (queryType) {
const rootQueryType = (introspection.__schema.types as any).find(
(t: any) => t.name == queryType.name
)
if (rootQueryType) {
;(introspection.__schema.types as any).Query = rootQueryType
;(introspection.__schema.types as any).Query.name = 'Query'
}
//////////////////////////////////////////////////////////////////////
//// Query and Mutation are properties, custom Types are definitions
//////////////////////////////////////////////////////////////////////
const [properties, definitions] = partition(
introspection.__schema.types,
type => isIntrospectionObjectType(type) && includes(['Query', 'Mutation'], type.name)
);
}
//////////////////////////////////////////////////////////////////////
//// Query and Mutation are properties, custom Types are definitions
//////////////////////////////////////////////////////////////////////
const [properties, definitions] = partition(
introspection.__schema.types,
(type) =>
isIntrospectionObjectType(type) &&
includes(['Query', 'Mutation'], type.name)
)
return {
$schema: 'http://json-schema.org/draft-06/schema#',
properties: reduce<IntrospectionType, JSONSchema6Acc>(
properties, introspectionTypeReducer('properties'), {}
),
definitions: reduce<IntrospectionType, JSONSchema6Acc>(
filterDefinitionsTypes(definitions, options), introspectionTypeReducer('definitions'), {}
)
};
};
return {
$schema: 'http://json-schema.org/draft-06/schema#',
properties: reduce<IntrospectionType, JSONSchema6Acc>(
properties,
introspectionTypeReducer('properties'),
{}
),
definitions: reduce<IntrospectionType, JSONSchema6Acc>(
filterDefinitionsTypes(definitions, options),
introspectionTypeReducer('definitions'),
{}
),
}
}

@@ -1,103 +0,115 @@

import { IntrospectionField, IntrospectionInputValue, IntrospectionScalarType, IntrospectionType } from 'graphql';
import { JSONSchema6 } from 'json-schema';
import { filter, map, MemoListIterator, reduce } from 'lodash';
import {
isIntrospectionEnumType,
isIntrospectionField,
isIntrospectionInputObjectType,
isIntrospectionInputValue,
isIntrospectionListTypeRef,
isIntrospectionObjectType,
isNonNullIntrospectionType,
isIntrospectionScalarType,
isIntrospectionDefaultScalarType
} from './typeGuards';
import { graphqlToJSONType, typesMapping } from './typesMapping';
IntrospectionField,
IntrospectionInputValue,
IntrospectionScalarType,
IntrospectionType,
} from 'graphql'
import { JSONSchema6 } from 'json-schema'
import { filter, map, MemoListIterator, reduce } from 'lodash'
import {
isIntrospectionEnumType,
isIntrospectionField,
isIntrospectionInputObjectType,
isIntrospectionInputValue,
isIntrospectionListTypeRef,
isIntrospectionObjectType,
isNonNullIntrospectionType,
isIntrospectionScalarType,
isIntrospectionDefaultScalarType,
} from './typeGuards'
import { graphqlToJSONType, typesMapping } from './typesMapping'
export type JSONSchema6Acc = {
[k: string]: JSONSchema6;
};
[k: string]: JSONSchema6
}
type GetRequiredFieldsType = ReadonlyArray<IntrospectionInputValue | IntrospectionField>;
type GetRequiredFieldsType = ReadonlyArray<
IntrospectionInputValue | IntrospectionField
>
// Extract GraphQL no-nullable types
export const getRequiredFields = (fields: GetRequiredFieldsType) => map(
filter(
fields,
f => {
// Not 100% sure if the GraphQL spec requires that NON_NULL should be
// the parent of LIST if it's both a NON_NULL and LIST field, but this
// should handle either case/implementation
return isIntrospectionListTypeRef(f.type) ?
isNonNullIntrospectionType(f.type.ofType) :
isNonNullIntrospectionType(f.type);
}
),
f => f.name
);
export const getRequiredFields = (fields: GetRequiredFieldsType) =>
map(
filter(fields, (f) => {
// Not 100% sure if the GraphQL spec requires that NON_NULL should be
// the parent of LIST if it's both a NON_NULL and LIST field, but this
// should handle either case/implementation
return isIntrospectionListTypeRef(f.type)
? isNonNullIntrospectionType(f.type.ofType)
: isNonNullIntrospectionType(f.type)
}),
(f) => f.name
)
export type IntrospectionFieldReducerItem = IntrospectionField | IntrospectionInputValue;
export type IntrospectionFieldReducerItem =
| IntrospectionField
| IntrospectionInputValue
// reducer for a queries/mutations
export const propertiesIntrospectionFieldReducer:
MemoListIterator<IntrospectionFieldReducerItem, JSONSchema6Acc, ReadonlyArray<IntrospectionFieldReducerItem>> =
(acc, curr: IntrospectionFieldReducerItem): JSONSchema6Acc => {
if (isIntrospectionField(curr)) {
const returnType = isNonNullIntrospectionType(curr.type) ?
graphqlToJSONType(curr.type.ofType) :
graphqlToJSONType(curr.type);
export const propertiesIntrospectionFieldReducer: MemoListIterator<
IntrospectionFieldReducerItem,
JSONSchema6Acc,
ReadonlyArray<IntrospectionFieldReducerItem>
> = (acc, curr: IntrospectionFieldReducerItem): JSONSchema6Acc => {
if (isIntrospectionField(curr)) {
const returnType = isNonNullIntrospectionType(curr.type)
? graphqlToJSONType(curr.type.ofType)
: graphqlToJSONType(curr.type)
acc[curr.name] = {
type: 'object',
properties: {
'return': returnType,
'arguments': {
type: 'object',
properties: reduce<IntrospectionFieldReducerItem, JSONSchema6Acc>(
curr.args as IntrospectionFieldReducerItem[], propertiesIntrospectionFieldReducer, {}
),
required: getRequiredFields(curr.args)
},
},
required: []
};
} else if (isIntrospectionInputValue(curr)) {
const returnType = isNonNullIntrospectionType(curr.type) ?
graphqlToJSONType(curr.type.ofType) :
graphqlToJSONType(curr.type);
acc[curr.name] = {
type: 'object',
properties: {
return: returnType,
arguments: {
type: 'object',
properties: reduce<IntrospectionFieldReducerItem, JSONSchema6Acc>(
curr.args as IntrospectionFieldReducerItem[],
propertiesIntrospectionFieldReducer,
{}
),
required: getRequiredFields(curr.args),
},
},
required: [],
}
} else if (isIntrospectionInputValue(curr)) {
const returnType = isNonNullIntrospectionType(curr.type)
? graphqlToJSONType(curr.type.ofType)
: graphqlToJSONType(curr.type)
acc[curr.name] = returnType;
if (curr.defaultValue) {
acc[curr.name].default = resolveDefaultValue(curr)
}
}
acc[curr.name] = returnType
if (curr.defaultValue) {
acc[curr.name].default = resolveDefaultValue(curr)
}
}
acc[curr.name].description = curr.description || undefined;
return acc;
};
acc[curr.name].description = curr.description || undefined
return acc
}
// reducer for a custom types
export const definitionsIntrospectionFieldReducer:
MemoListIterator<IntrospectionFieldReducerItem, JSONSchema6Acc, ReadonlyArray<IntrospectionFieldReducerItem>> =
(acc, curr: IntrospectionFieldReducerItem): JSONSchema6Acc => {
if (isIntrospectionField(curr)) {
const returnType = isNonNullIntrospectionType(curr.type) ?
graphqlToJSONType(curr.type.ofType) :
graphqlToJSONType(curr.type);
export const definitionsIntrospectionFieldReducer: MemoListIterator<
IntrospectionFieldReducerItem,
JSONSchema6Acc,
ReadonlyArray<IntrospectionFieldReducerItem>
> = (acc, curr: IntrospectionFieldReducerItem): JSONSchema6Acc => {
if (isIntrospectionField(curr)) {
const returnType = isNonNullIntrospectionType(curr.type)
? graphqlToJSONType(curr.type.ofType)
: graphqlToJSONType(curr.type)
acc[curr.name] = returnType;
} else if (isIntrospectionInputValue(curr)) {
const returnType = isNonNullIntrospectionType(curr.type) ?
graphqlToJSONType(curr.type.ofType) :
graphqlToJSONType(curr.type);
acc[curr.name] = returnType
} else if (isIntrospectionInputValue(curr)) {
const returnType = isNonNullIntrospectionType(curr.type)
? graphqlToJSONType(curr.type.ofType)
: graphqlToJSONType(curr.type)
acc[curr.name] = returnType;
if (curr.defaultValue) {
acc[curr.name].default = resolveDefaultValue(curr)
}
}
acc[curr.name] = returnType
if (curr.defaultValue) {
acc[curr.name].default = resolveDefaultValue(curr)
}
}
acc[curr.name].description = curr.description || undefined;
return acc;
};
acc[curr.name].description = curr.description || undefined
return acc
}

@@ -108,60 +120,66 @@ // ENUM type defaults will not JSON.parse correctly, so if it is an ENUM then don't

export const resolveDefaultValue = (curr: any) => {
return isIntrospectionEnumType(curr.type) ?
curr.defaultValue :
JSON.parse(curr.defaultValue);
return isIntrospectionEnumType(curr.type)
? curr.defaultValue
: JSON.parse(curr.defaultValue)
}
// Reducer for each type exposed by the GraphQL Schema
export const introspectionTypeReducer:
(type: 'definitions' | 'properties') => MemoListIterator<IntrospectionType, JSONSchema6Acc, IntrospectionType[]> =
type => (acc, curr: IntrospectionType): JSONSchema6Acc => {
const fieldReducer = type === 'definitions' ?
definitionsIntrospectionFieldReducer :
propertiesIntrospectionFieldReducer;
export const introspectionTypeReducer: (
type: 'definitions' | 'properties'
) => MemoListIterator<
IntrospectionType,
JSONSchema6Acc,
IntrospectionType[]
> = (type) => (acc, curr: IntrospectionType): JSONSchema6Acc => {
const fieldReducer =
type === 'definitions'
? definitionsIntrospectionFieldReducer
: propertiesIntrospectionFieldReducer
if (isIntrospectionObjectType(curr)) {
acc[curr.name] = {
type: 'object',
properties: reduce<IntrospectionFieldReducerItem, JSONSchema6Acc>(
curr.fields as IntrospectionFieldReducerItem[], fieldReducer, {}
),
// ignore required for Mutations/Queries
required: type === 'definitions' ? getRequiredFields(curr.fields) : []
};
} else if (isIntrospectionInputObjectType(curr)) {
acc[curr.name] = {
type: 'object',
properties: reduce<IntrospectionFieldReducerItem, JSONSchema6Acc>(
curr.inputFields as IntrospectionFieldReducerItem[], fieldReducer, {}
),
required: getRequiredFields(curr.inputFields)
};
} else if (isIntrospectionEnumType(curr)) {
acc[curr.name] = {
type: 'string',
anyOf: curr.enumValues.map((item) => {
return {
enum: [
item.name,
],
title: item.description || item.name,
description: item.description || undefined
};
}),
};
} else if(isIntrospectionDefaultScalarType(curr)){
acc[curr.name] = {
type: (typesMapping as any)[curr.name],
title: curr.name
}
if (isIntrospectionObjectType(curr)) {
acc[curr.name] = {
type: 'object',
properties: reduce<IntrospectionFieldReducerItem, JSONSchema6Acc>(
curr.fields as IntrospectionFieldReducerItem[],
fieldReducer,
{}
),
// ignore required for Mutations/Queries
required: type === 'definitions' ? getRequiredFields(curr.fields) : [],
}
} else if (isIntrospectionInputObjectType(curr)) {
acc[curr.name] = {
type: 'object',
properties: reduce<IntrospectionFieldReducerItem, JSONSchema6Acc>(
curr.inputFields as IntrospectionFieldReducerItem[],
fieldReducer,
{}
),
required: getRequiredFields(curr.inputFields),
}
} else if (isIntrospectionEnumType(curr)) {
acc[curr.name] = {
type: 'string',
anyOf: curr.enumValues.map((item) => {
return {
enum: [item.name],
title: item.description || item.name,
description: item.description || undefined,
}
else if (isIntrospectionScalarType(curr)){
acc[(curr as IntrospectionScalarType).name] = {
type: 'object',
title: (curr as IntrospectionScalarType).name
};
}
}),
}
} else if (isIntrospectionDefaultScalarType(curr)) {
acc[curr.name] = {
type: (typesMapping as any)[curr.name],
title: curr.name,
}
} else if (isIntrospectionScalarType(curr)) {
acc[(curr as IntrospectionScalarType).name] = {
type: 'object',
title: (curr as IntrospectionScalarType).name,
}
}
acc[curr.name].description = curr.description || undefined;
return acc;
};
acc[curr.name].description = curr.description || undefined
return acc
}
import {
IntrospectionEnumType,
IntrospectionField,
IntrospectionInputObjectType,
IntrospectionInputTypeRef,
IntrospectionInputValue,
IntrospectionListTypeRef,
IntrospectionNamedTypeRef,
IntrospectionNonNullTypeRef,
IntrospectionObjectType,
IntrospectionOutputTypeRef,
IntrospectionSchema,
IntrospectionType,
IntrospectionTypeRef,
IntrospectionScalarType
} from 'graphql';
import { filter, has, startsWith, includes } from 'lodash';
IntrospectionEnumType,
IntrospectionField,
IntrospectionInputObjectType,
IntrospectionInputTypeRef,
IntrospectionInputValue,
IntrospectionListTypeRef,
IntrospectionNamedTypeRef,
IntrospectionNonNullTypeRef,
IntrospectionObjectType,
IntrospectionOutputTypeRef,
IntrospectionSchema,
IntrospectionType,
IntrospectionTypeRef,
IntrospectionScalarType,
} from 'graphql'
import { filter, has, startsWith, includes } from 'lodash'

@@ -23,56 +23,63 @@ ///////////////////

export const isIntrospectionField = (type: IntrospectionField | IntrospectionInputValue): type is IntrospectionField =>
has(type, 'args');
export const isIntrospectionField = (
type: IntrospectionField | IntrospectionInputValue
): type is IntrospectionField => has(type, 'args')
export const isIntrospectionInputValue =
(type: IntrospectionField | IntrospectionInputValue): type is IntrospectionInputValue =>
has(type, 'defaultValue');
export const isIntrospectionInputValue = (
type: IntrospectionField | IntrospectionInputValue
): type is IntrospectionInputValue => has(type, 'defaultValue')
// @ts-ignore
export const isIntrospectionListTypeRef =
(type: IntrospectionTypeRef | IntrospectionInputTypeRef | IntrospectionOutputTypeRef):
type is IntrospectionListTypeRef => (
type.kind === 'LIST'
);
export const isIntrospectionListTypeRef = (
type:
| IntrospectionTypeRef
| IntrospectionInputTypeRef
| IntrospectionOutputTypeRef
): type is IntrospectionListTypeRef => type.kind === 'LIST'
export const isIntrospectionObjectType = (type: IntrospectionSchema['types'][0]): type is IntrospectionObjectType => (
type.kind === 'OBJECT'
);
export const isIntrospectionObjectType = (
type: IntrospectionSchema['types'][0]
): type is IntrospectionObjectType => type.kind === 'OBJECT'
export const isIntrospectionInputObjectType =
(type: IntrospectionSchema['types'][0]): type is IntrospectionInputObjectType => (
type.kind === 'INPUT_OBJECT'
);
export const isIntrospectionInputObjectType = (
type: IntrospectionSchema['types'][0]
): type is IntrospectionInputObjectType => type.kind === 'INPUT_OBJECT'
export const isIntrospectionEnumType = (type: IntrospectionSchema['types'][0]): type is IntrospectionEnumType => (
type.kind === 'ENUM'
);
export const isIntrospectionEnumType = (
type: IntrospectionSchema['types'][0]
): type is IntrospectionEnumType => type.kind === 'ENUM'
export const isNonNullIntrospectionType =
(type: IntrospectionTypeRef): type is IntrospectionNonNullTypeRef<IntrospectionNamedTypeRef<IntrospectionType>> => (
type.kind === 'NON_NULL'
);
export const isIntrospectionScalarType = (type: IntrospectionSchema['types'][0]): type is IntrospectionScalarType => (
type.kind === 'SCALAR'
);
export const isNonNullIntrospectionType = (
type: IntrospectionTypeRef
): type is IntrospectionNonNullTypeRef<
IntrospectionNamedTypeRef<IntrospectionType>
> => type.kind === 'NON_NULL'
export const isIntrospectionScalarType = (
type: IntrospectionSchema['types'][0]
): type is IntrospectionScalarType => type.kind === 'SCALAR'
export const isIntrospectionDefaultScalarType = (type: IntrospectionSchema['types'][0]): type is IntrospectionScalarType => (
type.kind === 'SCALAR' && includes(['Boolean', 'String', 'Int', 'Float'], type.name)
);
export const isIntrospectionDefaultScalarType = (
type: IntrospectionSchema['types'][0]
): type is IntrospectionScalarType =>
type.kind === 'SCALAR' &&
includes(['Boolean', 'String', 'Int', 'Float'], type.name)
// Ignore all GraphQL native Scalars, directives, etc...
export interface FilterDefinitionsTypesOptions { ignoreInternals?: boolean; }
export const filterDefinitionsTypes =
(types: IntrospectionType[], opts?: FilterDefinitionsTypesOptions): IntrospectionType[] => {
const ignoreInternals = opts && opts.ignoreInternals;
return filter(
types,
type => (
(isIntrospectionObjectType(type) && !!type.fields) ||
(isIntrospectionInputObjectType(type) && !!type.inputFields) ||
(isIntrospectionEnumType(type) && !!type.enumValues) ||
(isIntrospectionScalarType(type) && !! type.name)
) &&
(!ignoreInternals || (ignoreInternals && !startsWith(type.name, '__')))
);
};
export interface FilterDefinitionsTypesOptions {
ignoreInternals?: boolean
}
export const filterDefinitionsTypes = (
types: IntrospectionType[],
opts?: FilterDefinitionsTypesOptions
): IntrospectionType[] => {
const ignoreInternals = opts && opts.ignoreInternals
return filter(
types,
(type) =>
((isIntrospectionObjectType(type) && !!type.fields) ||
(isIntrospectionInputObjectType(type) && !!type.inputFields) ||
(isIntrospectionEnumType(type) && !!type.enumValues) ||
(isIntrospectionScalarType(type) && !!type.name)) &&
(!ignoreInternals || (ignoreInternals && !startsWith(type.name, '__')))
)
}
import {
IntrospectionInputType,
IntrospectionInputTypeRef,
IntrospectionNamedTypeRef,
IntrospectionOutputType,
IntrospectionOutputTypeRef,
IntrospectionTypeRef,
} from 'graphql';
IntrospectionInputType,
IntrospectionInputTypeRef,
IntrospectionNamedTypeRef,
IntrospectionOutputType,
IntrospectionOutputTypeRef,
IntrospectionTypeRef,
} from 'graphql'
import { JSONSchema6, JSONSchema6TypeName } from 'json-schema'
import { includes } from 'lodash'
import {
JSONSchema6,
JSONSchema6TypeName
} from 'json-schema';
import { includes } from 'lodash';
import { isIntrospectionListTypeRef, isNonNullIntrospectionType } from './typeGuards';
isIntrospectionListTypeRef,
isNonNullIntrospectionType,
} from './typeGuards'
export type GraphQLTypeNames = 'String' | 'Int' | 'Float' | 'Boolean';
export type GraphQLTypeNames = 'String' | 'Int' | 'Float' | 'Boolean'
export const typesMapping: { [k in GraphQLTypeNames]: JSONSchema6TypeName } = {
'Boolean': 'boolean',
'String': 'string',
'Int': 'number',
'Float': 'number'
};
Boolean: 'boolean',
String: 'string',
Int: 'number',
Float: 'number',
}
// Convert a GraphQL Type to a valid JSON Schema type
export type GraphqlToJSONTypeArg = IntrospectionTypeRef | IntrospectionInputTypeRef | IntrospectionOutputTypeRef;
export type GraphqlToJSONTypeArg =
| IntrospectionTypeRef
| IntrospectionInputTypeRef
| IntrospectionOutputTypeRef
export const graphqlToJSONType = (k: GraphqlToJSONTypeArg): JSONSchema6 => {
if (isIntrospectionListTypeRef(k)) {
return {
type: 'array',
items: graphqlToJSONType(k.ofType)
};
} else if (isNonNullIntrospectionType(k)) {
return graphqlToJSONType(k.ofType);
} else {
const name = (k as IntrospectionNamedTypeRef<IntrospectionInputType | IntrospectionOutputType>).name;
return includes(['OBJECT', 'INPUT_OBJECT', 'ENUM', 'SCALAR'], k.kind) ?
includes(['OBJECT', 'INPUT_OBJECT', 'ENUM'], k.kind) ?
{ $ref: `#/definitions/${name}` } :
// tslint:disable-next-line:no-any
{ $ref: `#/definitions/${name}`,
type: (typesMapping as any)[name]
} :
{ type: (typesMapping as any)[name]}
;
if (isIntrospectionListTypeRef(k)) {
return {
type: 'array',
items: graphqlToJSONType(k.ofType),
}
};
} else if (isNonNullIntrospectionType(k)) {
return graphqlToJSONType(k.ofType)
} else {
const name = (k as IntrospectionNamedTypeRef<
IntrospectionInputType | IntrospectionOutputType
>).name
return includes(['OBJECT', 'INPUT_OBJECT', 'ENUM', 'SCALAR'], k.kind)
? includes(['OBJECT', 'INPUT_OBJECT', 'ENUM'], k.kind)
? { $ref: `#/definitions/${name}` }
: // tslint:disable-next-line:no-any
{ $ref: `#/definitions/${name}`, type: (typesMapping as any)[name] }
: { type: (typesMapping as any)[name] }
}
}
{
"name": "graphql-2-json-schema",
"version": "0.3.1-0",
"version": "0.3.1",
"main": "dist/index.js",

@@ -15,3 +15,5 @@ "repository": "git@github.com:wittydeveloper/graphql-to-json-schema.git",

"scripts": {
"test": "jest"
"test": "jest",
"prettier:check": "prettier -c \"**/*.ts\"",
"prettier:format": "prettier -w \"**/*.ts\""
},

@@ -27,2 +29,3 @@ "devDependencies": {

"jest": "^26.6.3",
"prettier": "^2.2.1",
"standard-version": "^9.1.0",

@@ -29,0 +32,0 @@ "ts-jest": "^26.4.4",

import {
buildSchema,
GraphQLSchema,
graphqlSync,
IntrospectionQuery,
getIntrospectionQuery
} from 'graphql';
import { JSONSchema6 } from 'json-schema';
buildSchema,
GraphQLSchema,
graphqlSync,
IntrospectionQuery,
getIntrospectionQuery,
} from 'graphql'
import { JSONSchema6 } from 'json-schema'
type GetTodoSchemaIntrospectionResult = {
schema: GraphQLSchema;
introspection: IntrospectionQuery;
};
schema: GraphQLSchema
introspection: IntrospectionQuery
}
export const getTodoSchemaIntrospection = (): GetTodoSchemaIntrospectionResult => {
const schema = buildSchema(`
const schema = buildSchema(`
"A ToDo Object"

@@ -57,134 +57,135 @@ type Todo {

}
`);
`)
const result = graphqlSync(schema, getIntrospectionQuery());
return {
introspection: (result.data as IntrospectionQuery),
schema
};
};
const result = graphqlSync(schema, getIntrospectionQuery())
return {
introspection: result.data as IntrospectionQuery,
schema,
}
}
export const todoSchemaAsJsonSchema: JSONSchema6 = {
$schema: 'http://json-schema.org/draft-06/schema#',
properties: {
Query: {
type: 'object',
properties: {
todo: {
type: 'object',
properties: {
arguments: {
type: 'object',
properties: {
id: { type: 'string', description: "todo identifier" },
isCompleted: { type: 'boolean', default: false }
},
required: ['id']
},
return: {
$ref: '#/definitions/Todo'
}
},
required: []
},
todos: {
type: 'object',
properties: {
arguments: {
type: 'object',
properties: {},
required: []
},
return: {
type: 'array',
items: { $ref: '#/definitions/Todo' }
}
},
required: []
}
$schema: 'http://json-schema.org/draft-06/schema#',
properties: {
Query: {
type: 'object',
properties: {
todo: {
type: 'object',
properties: {
arguments: {
type: 'object',
properties: {
id: { type: 'string', description: 'todo identifier' },
isCompleted: { type: 'boolean', default: false },
},
required: ['id'],
},
required: []
return: {
$ref: '#/definitions/Todo',
},
},
required: [],
},
Mutation: {
type: 'object',
properties: {
update_todo: {
type: 'object',
properties: {
arguments: {
type: 'object',
properties: {
id: { type: 'string' },
todo: { $ref: '#/definitions/TodoInputType' }
},
required: ['id', 'todo']
},
return: {
$ref: '#/definitions/Todo'
}
},
required: []
},
create_todo: {
type: 'object',
properties: {
arguments: {
type: 'object',
properties: {
todo: { $ref: '#/definitions/TodoInputType' }
},
required: ['todo']
},
return: {
$ref: '#/definitions/Todo'
}
},
required: []
}
}
todos: {
type: 'object',
properties: {
arguments: {
type: 'object',
properties: {},
required: [],
},
return: {
type: 'array',
items: { $ref: '#/definitions/Todo' },
},
},
required: [],
},
},
required: [],
},
definitions: {
'Todo': {
type: 'object',
description: "A ToDo Object",
properties: {
id: { type: 'string', description: "A unique identifier" },
name: { type: 'string' },
completed: { type: 'boolean' },
color: { $ref: '#/definitions/Color' },
colors: {
description: "A list containing colors that cannot contain nulls",
type: 'array',
items: { $ref: '#/definitions/Color' }
},
Mutation: {
type: 'object',
properties: {
update_todo: {
type: 'object',
properties: {
arguments: {
type: 'object',
properties: {
id: { type: 'string' },
todo: { $ref: '#/definitions/TodoInputType' },
},
required: ['id', 'todo'],
},
required: ['id', 'name', 'colors']
return: {
$ref: '#/definitions/Todo',
},
},
required: [],
},
'Color': {
type: 'string',
anyOf: [
{
enum: ['RED'],
title: 'Red color',
description: 'Red color'
},
{
enum: ['GREEN'],
title: 'Green color',
description: 'Green color'
}
]
create_todo: {
type: 'object',
properties: {
arguments: {
type: 'object',
properties: {
todo: { $ref: '#/definitions/TodoInputType' },
},
required: ['todo'],
},
return: {
$ref: '#/definitions/Todo',
},
},
required: [],
},
'TodoInputType': {
type: 'object',
description: 'A type that describes ToDoInputType. Its description might not\nfit within the bounds of 80 width and so you want MULTILINE',
properties: {
name: { type: 'string' },
completed: { type: 'boolean' },
color: { default: 'RED', $ref: '#/definitions/Color' },
},
required: ['name']
}
}
};
},
},
},
definitions: {
Todo: {
type: 'object',
description: 'A ToDo Object',
properties: {
id: { type: 'string', description: 'A unique identifier' },
name: { type: 'string' },
completed: { type: 'boolean' },
color: { $ref: '#/definitions/Color' },
colors: {
description: 'A list containing colors that cannot contain nulls',
type: 'array',
items: { $ref: '#/definitions/Color' },
},
},
required: ['id', 'name', 'colors'],
},
Color: {
type: 'string',
anyOf: [
{
enum: ['RED'],
title: 'Red color',
description: 'Red color',
},
{
enum: ['GREEN'],
title: 'Green color',
description: 'Green color',
},
],
},
TodoInputType: {
type: 'object',
description:
'A type that describes ToDoInputType. Its description might not\nfit within the bounds of 80 width and so you want MULTILINE',
properties: {
name: { type: 'string' },
completed: { type: 'boolean' },
color: { default: 'RED', $ref: '#/definitions/Color' },
},
required: ['name'],
},
},
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc