Skip to content

Commit

Permalink
fix: accept graphql files that only consist of comments
Browse files Browse the repository at this point in the history
We already allowed whitespace-only files, so it only makes sense
to also allow comment-only files.
  • Loading branch information
Yogu committed Sep 13, 2024
1 parent 9636341 commit aad57b0
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 4 deletions.
98 changes: 96 additions & 2 deletions spec/project/project.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import { expect } from 'chai';
import { graphql } from 'graphql';
import { Logger, LoggerProvider } from '../../src/config/logging';
import { DatabaseAdapter, FlexSearchTokenizable } from '../../src/database/database-adapter';
import { FlexSearchLanguage, Model } from '../../src/model';
import { Model } from '../../src/model';
import { Project } from '../../src/project/project';
import { ProjectSource } from '../../src/project/source';
import { QueryNode } from '../../src/query-tree';
import { FlexSearchTokenization } from '../../src/query-tree/flex-search';
import { createSchema } from '../../src/schema/schema-builder';
import gql from 'graphql-tag';
import { expectSingleError, expectToBeValid } from '../model/implementation/validation-utils';

class FakeDBAdatper implements DatabaseAdapter {
async execute(queryTree: QueryNode): Promise<any> {
Expand All @@ -30,6 +31,99 @@ class FakeDBAdatper implements DatabaseAdapter {
}

describe('project', () => {
describe('validate', () => {
it('accepts a valid simple project', async () => {
const project = new Project([
gql`
type Test @rootEntity {
key: String @key
}
`.loc!.source,
]);
expectToBeValid(project);
});

it('accepts a valid project with multiple sources', async () => {
const project = new Project([
gql`
type Test @rootEntity {
key: String @key
children: [Child]
}
`.loc!.source,
gql`
# make sure this file is not skipped just because it begins with a comment
type Child @childEntity {
key: String
}
`.loc!.source,
]);
expectToBeValid(project);
});

it('rejects an invalid project with multiple sources', async () => {
const project = new Project([
gql`
type Test @rootEntity {
key: String @key
children: [Child]
}
`.loc!.source,
gql`
type OtherChild @childEntity {
key: String
}
`.loc!.source,
]);
expectSingleError(project, 'Type "Child" not found.');
});

it('accepts a valid project with an additional empty file', async () => {
const project = new Project([
gql`
type Test @rootEntity {
key: String @key
}
`.loc!.source,
{
name: 'other.graphqls',
body: '',
},
]);
expectToBeValid(project);
});

it('accepts a valid project with an additional file that only contains comments', async () => {
const project = new Project([
gql`
type Test @rootEntity {
key: String @key
}
`.loc!.source,
{
name: 'other.graphqls',
body: '# this is a comment',
},
]);
expectToBeValid(project);
});

it('accepts a project without any source', async () => {
const project = new Project([]);
expectToBeValid(project);
});

it('accepts a project with just a comment-only source', async () => {
const project = new Project([
{
name: 'other.graphqls',
body: '# this is a comment',
},
]);
expectToBeValid(project);
});
});

describe('createSchema', () => {
it('schema resolvers log to logger specified in project', async () => {
let logs: string[] = [];
Expand Down
21 changes: 21 additions & 0 deletions src/graphql/is-comment-only-source.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { GraphQLError, Lexer, TokenKind } from 'graphql/index';
import { Source } from 'graphql';

/**
* Checks if the given graphql source string only contains comments and whitespace
* @param source
*/
export function isCommentOnlySource(source: string) {
const lexer = new Lexer(new Source(source));
try {
// lookahead() gets the first non-comment token
const firstToken = lexer.lookahead();
return firstToken.kind === TokenKind.EOF;
} catch (e) {
if (e instanceof GraphQLError) {
// syntax error means there is something
return false;
}
throw e;
}
}
9 changes: 7 additions & 2 deletions src/schema/schema-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import {
getLocation,
GraphQLError,
GraphQLSchema,
parse,
Kind as GraphQLKind,
Lexer,
parse,
TokenKind,
} from 'graphql';
import { parse as JSONparse } from 'json-source-map';
import { compact } from 'lodash';
Expand Down Expand Up @@ -53,6 +55,7 @@ import {
import { getLineEndPosition } from './schema-utils';
import jsonLint = require('json-lint');
import stripJsonComments = require('strip-json-comments');
import { isCommentOnlySource } from '../graphql/is-comment-only-source';

/**
* Validates a project and thus determines whether createSchema() would succeed
Expand Down Expand Up @@ -311,7 +314,9 @@ function parseGraphQLsSource(
options: ProjectOptions,
validationContext: ValidationContext,
): ParsedGraphQLProjectSource | undefined {
if (projectSource.body.trim() === '') {
// parse() does not accept documents, and there is no option to make it accept them either
// it would be annoying if you could not have empty files
if (isCommentOnlySource(projectSource.body)) {
return undefined;
}

Expand Down

0 comments on commit aad57b0

Please sign in to comment.