Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions packages/apollo-language-server/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as cosmiconfig from "cosmiconfig";
import { LoaderEntry } from "cosmiconfig";
import TypeScriptLoader from "@endemolshinegroup/cosmiconfig-typescript-loader";
import { resolve } from "path";
import { resolve, dirname } from "path";
import { readFileSync, existsSync } from "fs";
import { merge } from "lodash/fp";

Expand Down Expand Up @@ -153,13 +153,14 @@ export type ConfigResult<Config> = {
// take a config with multiple project types and return
// an array of individual types
export const projectsFromConfig = (
config: ApolloConfigFormat
config: ApolloConfigFormat,
configURI?: URI
): Array<ClientConfig | ServiceConfig> => {
const configs = [];
const { client, service, ...rest } = config;
// XXX use casting detection
if (client) configs.push(new ClientConfig(config));
if (service) configs.push(new ServiceConfig(config));
if (client) configs.push(new ClientConfig(config, configURI));
if (service) configs.push(new ServiceConfig(config, configURI));
return configs;
};

Expand Down Expand Up @@ -204,8 +205,14 @@ export class ApolloConfig {
this.service = rawConfig.service;
}

get configDirURI() {
return this.configURI && this.configURI.fsPath.includes(".js")
? URI.parse(dirname(this.configURI.fsPath))
: this.configURI;
}

get projects() {
return projectsFromConfig(this.rawConfig);
return projectsFromConfig(this.rawConfig, this.configURI);
}

set tag(tag: string) {
Expand Down
17 changes: 9 additions & 8 deletions packages/apollo-language-server/src/fileSet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,33 @@ import { relative } from "path";
import minimatch = require("minimatch");
import * as glob from "glob";
import { invariant } from "@apollographql/apollo-tools";
import URI from "vscode-uri";
Comment thread
JakeDawkins marked this conversation as resolved.

export class FileSet {
private rootPath: string;
private rootURI: URI;
private includes: string[];
private excludes: string[];

constructor({
rootPath,
rootURI,
includes,
excludes
}: {
rootPath: string;
rootURI: URI;
includes: string[];
excludes: string[];
}) {
invariant(rootPath, `Must provide "rootPath".`);
invariant(rootURI, `Must provide "rootURI".`);
invariant(includes, `Must provide "includes".`);
invariant(excludes, `Must provide "excludes".`);

this.rootPath = rootPath;
this.rootURI = rootURI;
this.includes = includes;
this.excludes = excludes;
}

includesFile(filePath: string): boolean {
filePath = relative(this.rootPath, filePath);
filePath = relative(this.rootURI.fsPath, filePath);

return (
this.includes.some(include => minimatch(filePath, include)) &&
Expand All @@ -38,12 +39,12 @@ export class FileSet {
allFiles(): string[] {
return this.includes
.flatMap(include =>
glob.sync(include, { cwd: this.rootPath, absolute: true })
glob.sync(include, { cwd: this.rootURI.fsPath, absolute: true })
)
.filter(
filePath =>
!this.excludes.some(exclude =>
minimatch(relative(this.rootPath, filePath), exclude)
minimatch(relative(this.rootURI.fsPath, filePath), exclude)
)
);
}
Expand Down
9 changes: 9 additions & 0 deletions packages/apollo-language-server/src/languageProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ function symbolForFieldDefinition(
export class GraphQLLanguageProvider {
constructor(public workspace: GraphQLWorkspace) {}

async provideStats(uri?: DocumentUri) {
if (this.workspace.projects.length && uri) {
const project = this.workspace.projectForFile(uri);
return project ? project.getProjectStats() : { loaded: false };
}

return { loaded: false };
}

async provideCompletionItems(
uri: DocumentUri,
position: Position,
Expand Down
30 changes: 26 additions & 4 deletions packages/apollo-language-server/src/project/base.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { extname } from "path";
import { readFileSync } from "fs";
import Uri from "vscode-uri";
import URI from "vscode-uri";

import {
TypeSystemDefinitionNode,
Expand Down Expand Up @@ -48,6 +48,22 @@ export interface GraphQLProjectConfig {
fileSet: FileSet;
loadingHandler: LoadingHandler;
}

export interface TypeStats {
service?: number;
client?: number;
total?: number;
}

export interface ProjectStats {
type: string;
loaded: boolean;
serviceId?: string;
types?: TypeStats;
tag?: string;
lastFetch?: number;
}

export abstract class GraphQLProject implements GraphQLSchemaProvider {
public schemaProvider: GraphQLSchemaProvider;
protected _onDiagnostics?: NotificationHandler<PublishDiagnosticsParams>;
Expand All @@ -65,6 +81,8 @@ export abstract class GraphQLProject implements GraphQLSchemaProvider {
private fileSet: FileSet;
protected loadingHandler: LoadingHandler;

protected lastLoadDate?: number;

constructor({
config,
fileSet,
Expand Down Expand Up @@ -106,6 +124,8 @@ export abstract class GraphQLProject implements GraphQLSchemaProvider {

protected abstract initialize(): Promise<void>[];

abstract getProjectStats(): ProjectStats;

get isReady(): boolean {
return this._isReady;
}
Expand All @@ -124,10 +144,12 @@ export abstract class GraphQLProject implements GraphQLSchemaProvider {
}

public resolveSchema(config: SchemaResolveConfig): Promise<GraphQLSchema> {
this.lastLoadDate = +new Date();
return this.schemaProvider.resolveSchema(config);
}

public onSchemaChange(handler: NotificationHandler<GraphQLSchema>) {
this.lastLoadDate = +new Date();
return this.schemaProvider.onSchemaChange(handler);
}

Expand All @@ -136,15 +158,15 @@ export abstract class GraphQLProject implements GraphQLSchemaProvider {
}

includesFile(uri: DocumentUri) {
return this.fileSet.includesFile(Uri.parse(uri).fsPath);
return this.fileSet.includesFile(URI.parse(uri).fsPath);
}

async scanAllIncludedFiles() {
await this.loadingHandler.handle(
`Loading queries for ${this.displayName}`,
(async () => {
for (const filePath of this.fileSet.allFiles()) {
const uri = Uri.file(filePath).toString();
const uri = URI.file(filePath).toString();

// If we already have query documents for this file, that means it was either
// opened or changed before we got a chance to read it.
Expand All @@ -157,7 +179,7 @@ export abstract class GraphQLProject implements GraphQLSchemaProvider {
}

fileDidChange(uri: DocumentUri) {
const filePath = Uri.parse(uri).fsPath;
const filePath = URI.parse(uri).fsPath;
const extension = extname(filePath);
const languageId = fileAssociations[extension];

Expand Down
32 changes: 31 additions & 1 deletion packages/apollo-language-server/src/project/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ export class GraphQLClientProject extends GraphQLProject {
clientIdentity
}: GraphQLClientProjectConfig) {
const fileSet = new FileSet({
rootPath: rootURI.fsPath,
// the URI of the folder _containing_ the apollo.config.js is the true project's root.
// if a config doesn't have a uri associated, we can assume the `rootURI` is the project's root.
rootURI: config.configDirURI || rootURI,
includes: config.client.includes,
excludes: config.client.excludes
});
Expand All @@ -111,6 +113,33 @@ export class GraphQLClientProject extends GraphQLProject {
return [this.scanAllIncludedFiles(), this.loadServiceSchema()];
}

public getProjectStats() {
// use this to remove primitives and internal fields for stats
const filterTypes = (type: string) =>
!/^__|Boolean|ID|Int|String|Float/.test(type);

// filter out primitives and internal Types for type stats to match engine
const serviceTypes = this.serviceSchema
? Object.keys(this.serviceSchema.getTypeMap()).filter(filterTypes).length
: 0;
const totalTypes = this.schema
? Object.keys(this.schema.getTypeMap()).filter(filterTypes).length
: 0;

return {
type: "client",
serviceId: this.serviceID,
types: {
service: serviceTypes,
client: totalTypes - serviceTypes,
total: totalTypes
},
tag: this.config.tag,
loaded: this.serviceID ? true : false,
lastFetch: this.lastLoadDate
};
}

onDecorations(handler: (any: any) => void) {
this._onDecorations = handler;
}
Expand Down Expand Up @@ -213,6 +242,7 @@ export class GraphQLClientProject extends GraphQLProject {
] = await engineClient.loadSchemaTagsAndFieldStats(serviceID);
this._onSchemaTags && this._onSchemaTags([serviceID, schemaTags]);
this.fieldStats = fieldStats;
this.lastLoadDate = +new Date();

this.generateDecorations();
})()
Expand Down
6 changes: 5 additions & 1 deletion packages/apollo-language-server/src/project/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class GraphQLServiceProject extends GraphQLProject {
loadingHandler
}: GraphQLServiceProjectConfig) {
const fileSet = new FileSet({
rootPath: rootURI.fsPath,
rootURI: config.configDirURI || rootURI,
includes: config.service.includes,
excludes: config.service.excludes
});
Expand All @@ -43,4 +43,8 @@ export class GraphQLServiceProject extends GraphQLProject {
}

validate() {}

getProjectStats() {
return { loaded: true, type: "service" };
}
}
5 changes: 5 additions & 0 deletions packages/apollo-language-server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,5 +212,10 @@ connection.onNotification(
(selection: QuickPickItem) => workspace.updateSchemaTag(selection)
);

connection.onNotification("apollographql/getStats", async ({ uri }) => {
const status = await languageProvider.provideStats(uri);
connection.sendNotification("apollographql/statsLoaded", status);
});

// Listen on the connection
connection.listen();
9 changes: 4 additions & 5 deletions packages/apollo-language-server/src/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
NotificationHandler,
PublishDiagnosticsParams
} from "vscode-languageserver";
import Uri from "vscode-uri";
import { QuickPickItem } from "vscode";

import { GraphQLProject, DocumentUri } from "./project/base";
Expand Down Expand Up @@ -54,13 +53,13 @@ export class GraphQLWorkspace {
? new GraphQLClientProject({
config,
loadingHandler: this.LanguageServerLoadingHandler,
rootURI: URI.file(folder.uri),
rootURI: URI.parse(folder.uri),
clientIdentity
})
: new GraphQLServiceProject({
config: config as ServiceConfig,
loadingHandler: this.LanguageServerLoadingHandler,
rootURI: URI.file(folder.uri),
rootURI: URI.parse(folder.uri),
clientIdentity
});

Expand Down Expand Up @@ -98,14 +97,14 @@ export class GraphQLWorkspace {

*/
const apolloConfigFiles: string[] = fg.sync("**/apollo.config.@(js|ts)", {
cwd: Uri.parse(folder.uri).fsPath,
cwd: URI.parse(folder.uri).fsPath,
absolute: true,
ignore: "**/node_modules/**"
});

apolloConfigFiles.push(
...fg.sync("**/package.json", {
cwd: Uri.parse(folder.uri).fsPath,
cwd: URI.parse(folder.uri).fsPath,
absolute: true,
ignore: "**/node_modules/**"
})
Expand Down
6 changes: 2 additions & 4 deletions packages/apollo/src/commands/client/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ import * as path from "path";
import { Kind, DocumentNode } from "graphql";
import * as tty from "tty";
import { Gaze } from "gaze";

import Uri from "vscode-uri";
import URI from "vscode-uri";

import { TargetType, default as generate } from "../../generate";

import { ClientCommand } from "../../Command";
import URI from "vscode-uri";

const waitForKey = async () => {
console.log("Press any key to stop.");
Expand Down Expand Up @@ -218,7 +216,7 @@ export default class Generate extends ClientCommand {
const watcher = new Gaze(this.project.config.client.includes);
watcher.on("all", (event, file) => {
// console.log("\nChange detected, generating types...");
this.project.fileDidChange(Uri.file(file).toString());
this.project.fileDidChange(URI.file(file).toString());
});
if (tty.isatty((process.stdin as any).fd)) {
await waitForKey();
Expand Down
4 changes: 2 additions & 2 deletions packages/apollo/src/generate.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { fs } from "apollo-codegen-core/lib/localfs";
import * as path from "path";
import { GraphQLSchema, DocumentNode, print } from "graphql";
import Uri from "vscode-uri";
import URI from "vscode-uri";

import {
compileToIR,
Expand Down Expand Up @@ -42,7 +42,7 @@ export type GenerationOptions = CompilerOptions &
};

function toPath(uri: string): string {
return Uri.parse(uri).path;
return URI.parse(uri).path;
}

export default function generate(
Expand Down
5 changes: 5 additions & 0 deletions packages/vscode-apollo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@
"command": "apollographql/reloadService",
"title": "Reload schema",
"category": "Apollo"
},
{
"command": "apollographql/showStatus",
"title": "Show Status",
"category": "Apollo"
}
]
}
Expand Down
Loading