UNPKG

@platformos/pos-cli

Version:

Manage your platformOS application

162 lines 7.64 kB
import { Kind, parse, print } from 'graphql'; import { getAutocompleteSuggestions } from './getAutocompleteSuggestions'; import { getHoverInformation } from './getHoverInformation'; import { validateQuery, getRange, SEVERITY } from './getDiagnostics'; import { getDefinitionQueryResultForFragmentSpread, getDefinitionQueryResultForDefinitionNode, getDefinitionQueryResultForNamedType, } from './getDefinition'; import { getASTNodeAtPosition, requireFile, resolveFile } from 'graphql-language-service-utils'; const { FRAGMENT_DEFINITION, OBJECT_TYPE_DEFINITION, INTERFACE_TYPE_DEFINITION, ENUM_TYPE_DEFINITION, UNION_TYPE_DEFINITION, SCALAR_TYPE_DEFINITION, INPUT_OBJECT_TYPE_DEFINITION, SCALAR_TYPE_EXTENSION, OBJECT_TYPE_EXTENSION, INTERFACE_TYPE_EXTENSION, UNION_TYPE_EXTENSION, ENUM_TYPE_EXTENSION, INPUT_OBJECT_TYPE_EXTENSION, DIRECTIVE_DEFINITION, FRAGMENT_SPREAD, OPERATION_DEFINITION, NAMED_TYPE, } = Kind; export class GraphQLLanguageService { constructor(cache) { this._graphQLCache = cache; this._graphQLConfig = cache.getGraphQLConfig(); } getConfigForURI(uri) { const config = this._graphQLConfig.getConfigForFile(uri); if (config) { return config; } throw Error(`No config found for uri: ${uri}`); } async getDiagnostics(query, uri, isRelayCompatMode) { let queryHasExtensions = false; const projectConfig = this.getConfigForURI(uri); const { schemaPath, projectName, extensions } = projectConfig; try { const queryAST = parse(query); if (!schemaPath || uri !== schemaPath) { queryHasExtensions = queryAST.definitions.some(definition => { switch (definition.kind) { case OBJECT_TYPE_DEFINITION: case INTERFACE_TYPE_DEFINITION: case ENUM_TYPE_DEFINITION: case UNION_TYPE_DEFINITION: case SCALAR_TYPE_DEFINITION: case INPUT_OBJECT_TYPE_DEFINITION: case SCALAR_TYPE_EXTENSION: case OBJECT_TYPE_EXTENSION: case INTERFACE_TYPE_EXTENSION: case UNION_TYPE_EXTENSION: case ENUM_TYPE_EXTENSION: case INPUT_OBJECT_TYPE_EXTENSION: case DIRECTIVE_DEFINITION: return true; } return false; }); } } catch (error) { const range = getRange(error.locations[0], query); return [ { severity: SEVERITY.ERROR, message: error.message, source: 'GraphQL: Syntax', range, }, ]; } let source = query; const fragmentDefinitions = await this._graphQLCache.getFragmentDefinitions(projectConfig); const fragmentDependencies = await this._graphQLCache.getFragmentDependencies(query, fragmentDefinitions); const dependenciesSource = fragmentDependencies.reduce((prev, cur) => `${prev} ${print(cur.definition)}`, ''); source = `${source} ${dependenciesSource}`; let validationAst = null; try { validationAst = parse(source); } catch (error) { return []; } let customRules; const customRulesModulePath = extensions.customValidationRules; if (customRulesModulePath) { const rulesPath = resolveFile(customRulesModulePath); if (rulesPath) { const customValidationRules = await requireFile(rulesPath); if (customValidationRules) { customRules = customValidationRules(this._graphQLConfig); } } } const schema = await this._graphQLCache .getSchema(projectName, queryHasExtensions) .catch(() => null); if (!schema) { return []; } return validateQuery(validationAst, schema, customRules, isRelayCompatMode); } async getAutocompleteSuggestions(query, position, filePath) { const projectConfig = this.getConfigForURI(filePath); const schema = await this._graphQLCache .getSchema(projectConfig.projectName) .catch(() => null); if (schema) { return getAutocompleteSuggestions(schema, query, position); } return []; } async getHoverInformation(query, position, filePath) { const projectConfig = this.getConfigForURI(filePath); const schema = await this._graphQLCache .getSchema(projectConfig.projectName) .catch(() => null); if (schema) { return getHoverInformation(schema, query, position); } return ''; } async getDefinition(query, position, filePath) { const projectConfig = this.getConfigForURI(filePath); let ast; try { ast = parse(query); } catch (error) { return null; } const node = getASTNodeAtPosition(query, ast, position); if (node) { switch (node.kind) { case FRAGMENT_SPREAD: return this._getDefinitionForFragmentSpread(query, ast, node, filePath, projectConfig); case FRAGMENT_DEFINITION: case OPERATION_DEFINITION: return getDefinitionQueryResultForDefinitionNode(filePath, query, node); case NAMED_TYPE: return this._getDefinitionForNamedType(query, ast, node, filePath, projectConfig); } } return null; } async _getDefinitionForNamedType(query, ast, node, filePath, projectConfig) { const objectTypeDefinitions = await this._graphQLCache.getObjectTypeDefinitions(projectConfig); const dependencies = await this._graphQLCache.getObjectTypeDependenciesForAST(ast, objectTypeDefinitions); const localObjectTypeDefinitions = ast.definitions.filter(definition => definition.kind === OBJECT_TYPE_DEFINITION || definition.kind === INPUT_OBJECT_TYPE_DEFINITION || definition.kind === ENUM_TYPE_DEFINITION); const typeCastedDefs = localObjectTypeDefinitions; const localOperationDefinationInfos = typeCastedDefs.map((definition) => ({ filePath, content: query, definition, })); const result = await getDefinitionQueryResultForNamedType(query, node, dependencies.concat(localOperationDefinationInfos)); return result; } async _getDefinitionForFragmentSpread(query, ast, node, filePath, projectConfig) { const fragmentDefinitions = await this._graphQLCache.getFragmentDefinitions(projectConfig); const dependencies = await this._graphQLCache.getFragmentDependenciesForAST(ast, fragmentDefinitions); const localFragDefinitions = ast.definitions.filter(definition => definition.kind === FRAGMENT_DEFINITION); const typeCastedDefs = localFragDefinitions; const localFragInfos = typeCastedDefs.map((definition) => ({ filePath, content: query, definition, })); const result = await getDefinitionQueryResultForFragmentSpread(query, node, dependencies.concat(localFragInfos)); return result; } } //# sourceMappingURL=GraphQLLanguageService.js.map