@platformos/pos-cli
Version:
Manage your platformOS application
162 lines • 7.64 kB
JavaScript
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