Skip to content

Commit

Permalink
feat: use new GraphQL Config (#1342)
Browse files Browse the repository at this point in the history
* fix: use new GraphQL Config

Co-authored-by: Arda TANRIKULU <20847995+ardatan@users.noreply.github.com>
  • Loading branch information
acao and ardatan committed Feb 16, 2020
1 parent f729f9a commit e45838f
Show file tree
Hide file tree
Showing 17 changed files with 452 additions and 273 deletions.
2 changes: 1 addition & 1 deletion packages/graphql-language-service-interface/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"graphql": "^0.12.0 || ^0.13.0 || ^14.0.0"
},
"dependencies": {
"graphql-config": "2.2.1",
"graphql-config": "3.0.0-alpha.17",
"graphql-language-service-parser": "^1.5.3-alpha.1",
"graphql-language-service-types": "^1.6.0-alpha.1",
"graphql-language-service-utils": "^2.4.0-alpha.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,13 @@ import {
DefinitionQueryResult,
Diagnostic,
GraphQLCache,
GraphQLConfig,
GraphQLProjectConfig,
Uri,
Position,
Outline,
OutlineTree,
} from 'graphql-language-service-types';

// import { Position } from 'graphql-language-service-utils';
import { GraphQLConfig, GraphQLProjectConfig } from 'graphql-config';
import {
Hover,
SymbolInformation,
Expand Down Expand Up @@ -111,7 +109,7 @@ export class GraphQLLanguageService {
}

getConfigForURI(uri: Uri) {
const config = this._graphQLConfig.getConfigForFile(uri);
const config = this._graphQLConfig.getProjectForFile(uri);
if (config) {
return config;
}
Expand All @@ -127,7 +125,7 @@ export class GraphQLLanguageService {
// schema/fragment definitions, even the project configuration.
let queryHasExtensions = false;
const projectConfig = this.getConfigForURI(uri);
const { schemaPath, projectName, extensions } = projectConfig;
const { schema: schemaPath, name: projectName, extensions } = projectConfig;

try {
const queryAST = parse(query);
Expand Down Expand Up @@ -228,7 +226,7 @@ export class GraphQLLanguageService {
): Promise<Array<CompletionItem>> {
const projectConfig = this.getConfigForURI(filePath);
const schema = await this._graphQLCache
.getSchema(projectConfig.projectName)
.getSchema(projectConfig.name)
.catch(() => null);

if (schema) {
Expand All @@ -244,7 +242,7 @@ export class GraphQLLanguageService {
): Promise<Hover['contents']> {
const projectConfig = this.getConfigForURI(filePath);
const schema = await this._graphQLCache
.getSchema(projectConfig.projectName)
.getSchema(projectConfig.name)
.catch(() => null);

if (schema) {
Expand Down Expand Up @@ -435,7 +433,7 @@ export class GraphQLLanguageService {

return result;
}
async getOutline(query: string): Promise<Outline | null | undefined> {
return getOutline(query);
async getOutline(documentText: string): Promise<Outline | null> {
return getOutline(documentText);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,29 @@
*/

import { join } from 'path';
import * as fs from 'fs';
import { buildSchema } from 'graphql';

import { GraphQLConfig } from 'graphql-config';
import { GraphQLLanguageService } from '../GraphQLLanguageService';
import { SymbolKind } from 'vscode-languageserver-protocol';
import { Position } from 'graphql-language-service-utils';

const MOCK_CONFIG = {
schemaPath: './__schema__/StarWarsSchema.graphql',
includes: ['./queries/**', '**/*.graphql'],
filepath: join(__dirname, '.graphqlrc.yml'),
config: {
schema: './__schema__/StarWarsSchema.graphql',
documents: ['./queries/**', '**/*.graphql'],
},
};

describe('GraphQLLanguageService', () => {
const mockCache: any = {
getSchema() {
const schemaSDL = fs.readFileSync(
join(__dirname, '__schema__/StarWarsSchema.graphql'),
'utf8',
);

const schemaJS = buildSchema(schemaSDL);
return new Promise((resolve, _reject) => resolve(schemaJS));
const mockCache = {
async getSchema() {
const config = this.getGraphQLConfig();
return config.getDefault()!.getSchema();
},

getGraphQLConfig() {
return new GraphQLConfig(MOCK_CONFIG, join(__dirname, '.graphqlconfig'));
return new GraphQLConfig(MOCK_CONFIG, []);
},

getObjectTypeDefinitions() {
Expand Down Expand Up @@ -78,7 +74,7 @@ describe('GraphQLLanguageService', () => {

let languageService: GraphQLLanguageService;
beforeEach(() => {
languageService = new GraphQLLanguageService(mockCache);
languageService = new GraphQLLanguageService(mockCache as any);
});

it('runs diagnostic service as expected', async () => {
Expand Down
6 changes: 3 additions & 3 deletions packages/graphql-language-service-interface/src/getOutline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,15 @@ type OutlineTreeConverterType = Partial<
}
>;

export function getOutline(queryText: string): Outline | null {
export function getOutline(documentText: string): Outline | null {
let ast;
try {
ast = parse(queryText);
ast = parse(documentText);
} catch (error) {
return null;
}

const visitorFns = outlineTreeConverter(queryText);
const visitorFns = outlineTreeConverter(documentText);
const outlineTrees = visit(ast, {
leave(node) {
if (visitorFns !== undefined && node.kind in visitorFns) {
Expand Down
2 changes: 1 addition & 1 deletion packages/graphql-language-service-parser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"graphql": "^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0"
},
"dependencies": {
"graphql-config": "2.2.1",
"graphql-config": "3.0.0-alpha.17",
"graphql-language-service-types": "^1.6.0-alpha.1"
}
}
2 changes: 1 addition & 1 deletion packages/graphql-language-service-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"dependencies": {
"@babel/parser": "^7.4.5",
"glob": "^7.1.2",
"graphql-config": "2.2.1",
"graphql-config": "3.0.0-alpha.17",
"graphql-language-service-interface": "^2.4.0-alpha.1",
"graphql-language-service-types": "^1.6.0-alpha.1",
"graphql-language-service-utils": "^2.4.0-alpha.1",
Expand Down
115 changes: 31 additions & 84 deletions packages/graphql-language-service-server/src/GraphQLCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,21 @@ import { ASTNode, DocumentNode, DefinitionNode } from 'graphql/language';
import {
CachedContent,
GraphQLCache as GraphQLCacheInterface,
GraphQLConfig as GraphQLConfigInterface,
GraphQLFileMetadata,
GraphQLFileInfo,
FragmentInfo,
ObjectTypeInfo,
Uri,
GraphQLProjectConfig,
} from 'graphql-language-service-types';

import * as fs from 'fs';
import { GraphQLSchema, Kind, extendSchema, parse, visit } from 'graphql';
import nullthrows from 'nullthrows';

import {
getGraphQLConfig,
loadConfig,
GraphQLConfig,
GraphQLEndpoint,
GraphQLProjectConfig,
} from 'graphql-config';
import { getQueryAndRange } from './MessageProcessor';
import stringToHash from './stringToHash';
Expand All @@ -54,8 +52,10 @@ const {
DIRECTIVE_DEFINITION,
} = Kind;

export async function getGraphQLCache(configDir: Uri): Promise<GraphQLCache> {
const graphQLConfig = await getGraphQLConfig(configDir);
export async function getGraphQLCache(
configDir: Uri,
): Promise<GraphQLCacheInterface> {
const graphQLConfig = await loadConfig({ rootDir: configDir });
return new GraphQLCache(configDir, graphQLConfig);
}

Expand All @@ -78,7 +78,7 @@ export class GraphQLCache implements GraphQLCacheInterface {
this._typeExtensionMap = new Map();
}

getGraphQLConfig = (): GraphQLConfigInterface => this._graphQLConfig;
getGraphQLConfig = (): GraphQLConfig => this._graphQLConfig;

getFragmentDependencies = async (
query: string,
Expand Down Expand Up @@ -159,17 +159,21 @@ export class GraphQLCache implements GraphQLCacheInterface {
): Promise<Map<string, FragmentInfo>> => {
// This function may be called from other classes.
// If then, check the cache first.
const rootDir = projectConfig.configDir;
const rootDir = projectConfig.dirpath;
if (this._fragmentDefinitionsCache.has(rootDir)) {
return this._fragmentDefinitionsCache.get(rootDir) || new Map();
}

const filesFromInputDirs = await this._readFilesFromInputDirs(
rootDir,
projectConfig.includes,
projectConfig.include instanceof Array
? projectConfig.include
: projectConfig.include
? [projectConfig.include]
: [],
);
const list = filesFromInputDirs.filter(fileInfo =>
projectConfig.includesFile(fileInfo.filePath),
projectConfig.match(fileInfo.filePath),
);

const {
Expand Down Expand Up @@ -271,16 +275,20 @@ export class GraphQLCache implements GraphQLCacheInterface {
): Promise<Map<string, ObjectTypeInfo>> => {
// This function may be called from other classes.
// If then, check the cache first.
const rootDir = projectConfig.configDir;
const rootDir = projectConfig.dirpath;
if (this._typeDefinitionsCache.has(rootDir)) {
return this._typeDefinitionsCache.get(rootDir) || new Map();
}
const filesFromInputDirs = await this._readFilesFromInputDirs(
rootDir,
projectConfig.includes,
projectConfig.include instanceof Array
? projectConfig.include
: projectConfig.include
? [projectConfig.include]
: [],
);
const list = filesFromInputDirs.filter(fileInfo =>
projectConfig.includesFile(fileInfo.filePath),
projectConfig.match(fileInfo.filePath),
);
const {
objectTypeDefinitions,
Expand Down Expand Up @@ -589,44 +597,20 @@ export class GraphQLCache implements GraphQLCacheInterface {
appName?: string,
queryHasExtensions?: boolean | null,
): Promise<GraphQLSchema | null> => {
const projectConfig = this._graphQLConfig.getProjectConfig(appName);
const projectConfig = this._graphQLConfig.getProject(appName);

if (!projectConfig) {
return null;
}

const schemaPath = projectConfig.schemaPath;
const endpointInfo = this._getDefaultEndpoint(projectConfig);
const { endpointKey, schemaKey } = this._getSchemaCacheKeysForProject(
projectConfig,
);
const schemaPath = projectConfig.schema as string;
const schemaKey = this._getSchemaCacheKeyForProject(projectConfig);

let schemaCacheKey = null;
let schema = null;

if (endpointInfo && endpointKey) {
const { endpoint } = endpointInfo;
schemaCacheKey = endpointKey;

// Maybe use cache
if (this._schemaMap.has(schemaCacheKey)) {
schema = this._schemaMap.get(schemaCacheKey);
// @ts-ignore
return schema && queryHasExtensions
? this._extendSchema(schema, schemaPath, schemaCacheKey)
: schema;
}

// Read schema from network
try {
schema = await endpoint.resolveSchema();
} catch (failure) {
// Never mind
}
}

if (!schema && schemaPath && schemaKey) {
schemaCacheKey = schemaKey;
schemaCacheKey = schemaKey as string;

// Maybe use cache
if (this._schemaMap.has(schemaCacheKey)) {
Expand All @@ -639,7 +623,7 @@ export class GraphQLCache implements GraphQLCacheInterface {
}

// Read from disk
schema = projectConfig.getSchema();
schema = await projectConfig.getSchema();
}

const customDirectives = projectConfig.extensions.customDirectives;
Expand Down Expand Up @@ -669,55 +653,18 @@ export class GraphQLCache implements GraphQLCacheInterface {
};

_invalidateSchemaCacheForProject(projectConfig: GraphQLProjectConfig) {
const { endpointKey, schemaKey } = this._getSchemaCacheKeysForProject(
const schemaKey = this._getSchemaCacheKeyForProject(
projectConfig,
);
endpointKey && this._schemaMap.delete(endpointKey);
) as string;
schemaKey && this._schemaMap.delete(schemaKey);
}

_getSchemaCacheKeysForProject(projectConfig: GraphQLProjectConfig) {
const endpointInfo = this._getDefaultEndpoint(projectConfig);
const projectName = this._getProjectName(projectConfig);
return {
endpointKey: endpointInfo
? `${endpointInfo.endpointName}:${projectName}`
: null,
schemaKey: projectConfig.schemaPath
? `${projectConfig.schemaPath}:${projectName}`
: null,
};
_getSchemaCacheKeyForProject(projectConfig: GraphQLProjectConfig) {
return projectConfig.schema;
}

_getProjectName(projectConfig: GraphQLProjectConfig) {
return projectConfig || 'undefinedName';
}

_getDefaultEndpoint(
projectConfig: GraphQLProjectConfig,
): { endpointName: string; endpoint: GraphQLEndpoint } | null {
// Jumping through hoops to get the default endpoint by name (needed for cache key)
const endpointsExtension = projectConfig.endpointsExtension;
if (!endpointsExtension) {
return null;
}
// not public but needed
// @ts-ignore
const defaultRawEndpoint = endpointsExtension.getRawEndpoint();
const rawEndpointsMap = endpointsExtension.getRawEndpointsMap();

const endpointName = Object.keys(rawEndpointsMap).find(
name => rawEndpointsMap[name] === defaultRawEndpoint,
);

if (!endpointName) {
return null;
}

return {
endpointName,
endpoint: endpointsExtension.getEndpoint(endpointName),
};
return projectConfig || 'default';
}

/**
Expand Down
Loading

0 comments on commit e45838f

Please sign in to comment.