UNPKG

graphql-language-service

Version:

The official, runtime independent Language Service for GraphQL

204 lines 7.46 kB
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