graphql-language-service
Version:
The official, runtime independent Language Service for GraphQL
204 lines • 7.46 kB
JavaScript
import { isEnumType, isInputObjectType, isListType, isNonNullType, isScalarType, } from 'graphql';
export const defaultJSONSchemaOptions = {
useMarkdownDescription: false,
};
function text(into, newText) {
into.push(newText);
}
function renderType(into, t) {
if (isNonNullType(t)) {
renderType(into, t.ofType);
text(into, '!');
}
else if (isListType(t)) {
text(into, '[');
renderType(into, t.ofType);
text(into, ']');
}
else {
text(into, t.name);
}
}
function renderDefinitionDescription(t, useMarkdown, description) {
const into = [];
const type = 'type' in t ? t.type : t;
if ('type' in t && t.description) {
text(into, t.description);
text(into, '\n\n');
}
text(into, renderTypeToString(type, useMarkdown));
if (description) {
text(into, '\n');
text(into, description);
}
else if (!isScalarType(type) && 'description' in type && type.description) {
text(into, '\n');
text(into, type.description);
}
else if ('ofType' in type &&
!isScalarType(type.ofType) &&
'description' in type.ofType &&
type.ofType.description) {
text(into, '\n');
text(into, type.ofType.description);
}
return into.join('');
}
function renderTypeToString(t, useMarkdown) {
const into = [];
if (useMarkdown) {
text(into, '```graphql\n');
}
renderType(into, t);
if (useMarkdown) {
text(into, '\n```');
}
return into.join('');
}
const defaultScalarTypesMap = {
Int: { type: 'integer' },
String: { type: 'string' },
Float: { type: 'number' },
ID: { type: 'string' },
Boolean: { type: 'boolean' },
DateTime: { type: 'string' },
};
class Marker {
constructor() {
this.set = new Set();
}
mark(name) {
if (this.set.has(name)) {
return false;
}
this.set.add(name);
return true;
}
}
function getJSONSchemaFromGraphQLType(fieldOrType, options) {
var _a, _b;
let definition = Object.create(null);
const definitions = Object.create(null);
const isField = 'type' in fieldOrType;
const type = isField ? fieldOrType.type : fieldOrType;
const baseType = isNonNullType(type) ? type.ofType : type;
const required = isNonNullType(type);
if (isScalarType(baseType)) {
if ((_a = options === null || options === void 0 ? void 0 : options.scalarSchemas) === null || _a === void 0 ? void 0 : _a[baseType.name]) {
definition = JSON.parse(JSON.stringify(options.scalarSchemas[baseType.name]));
}
else {
definition.type = ['string', 'number', 'boolean', 'integer'];
}
if (!required) {
if (Array.isArray(definition.type)) {
definition.type.push('null');
}
else if (definition.type) {
definition.type = [definition.type, 'null'];
}
else if (definition.enum) {
definition.enum.push(null);
}
else if (definition.oneOf) {
definition.oneOf.push({ type: 'null' });
}
else {
definition = {
oneOf: [definition, { type: 'null' }],
};
}
}
}
else if (isEnumType(baseType)) {
definition.enum = baseType.getValues().map(val => val.name);
if (!required) {
definition.enum.push(null);
}
}
else if (isListType(baseType)) {
if (required) {
definition.type = 'array';
}
else {
definition.type = ['array', 'null'];
}
const { definition: def, definitions: defs } = getJSONSchemaFromGraphQLType(baseType.ofType, options);
definition.items = def;
if (defs) {
for (const defName of Object.keys(defs)) {
definitions[defName] = defs[defName];
}
}
}
else if (isInputObjectType(baseType)) {
if (required) {
definition.$ref = `#/definitions/${baseType.name}`;
}
else {
definition.oneOf = [
{ $ref: `#/definitions/${baseType.name}` },
{ type: 'null' },
];
}
if ((_b = options === null || options === void 0 ? void 0 : options.definitionMarker) === null || _b === void 0 ? void 0 : _b.mark(baseType.name)) {
const fields = baseType.getFields();
const fieldDef = {
type: 'object',
properties: {},
required: [],
};
fieldDef.description = renderDefinitionDescription(baseType);
if (options === null || options === void 0 ? void 0 : options.useMarkdownDescription) {
fieldDef.markdownDescription = renderDefinitionDescription(baseType, true);
}
for (const fieldName of Object.keys(fields)) {
const field = fields[fieldName];
const { required: fieldRequired, definition: fieldDefinition, definitions: typeDefinitions, } = getJSONSchemaFromGraphQLType(field, options);
fieldDef.properties[fieldName] = fieldDefinition;
if (fieldRequired) {
fieldDef.required.push(fieldName);
}
if (typeDefinitions) {
for (const [defName, value] of Object.entries(typeDefinitions)) {
definitions[defName] = value;
}
}
}
definitions[baseType.name] = fieldDef;
}
}
if ('defaultValue' in fieldOrType && fieldOrType.defaultValue !== undefined) {
definition.default = fieldOrType.defaultValue;
}
const { description } = definition;
definition.description = renderDefinitionDescription(fieldOrType, false, description);
if (options === null || options === void 0 ? void 0 : options.useMarkdownDescription) {
definition.markdownDescription = renderDefinitionDescription(fieldOrType, true, description);
}
return { required, definition, definitions };
}
export function getVariablesJSONSchema(variableToType, options) {
var _a;
const jsonSchema = {
$schema: 'http://json-schema.org/draft-04/schema',
type: 'object',
properties: {},
required: [],
};
const runtimeOptions = Object.assign(Object.assign({}, options), { definitionMarker: new Marker(), scalarSchemas: Object.assign(Object.assign({}, defaultScalarTypesMap), options === null || options === void 0 ? void 0 : options.scalarSchemas) });
if (variableToType) {
for (const [variableName, type] of Object.entries(variableToType)) {
const { definition, required, definitions } = getJSONSchemaFromGraphQLType(type, runtimeOptions);
jsonSchema.properties[variableName] = definition;
if (required) {
(_a = jsonSchema.required) === null || _a === void 0 ? void 0 : _a.push(variableName);
}
if (definitions) {
jsonSchema.definitions = Object.assign(Object.assign({}, jsonSchema === null || jsonSchema === void 0 ? void 0 : jsonSchema.definitions), definitions);
}
}
}
return jsonSchema;
}
//# sourceMappingURL=getVariablesJSONSchema.js.map