Skip to content

Commit

Permalink
Merge pull request #95 from cjoudrey/descriptions-as-strings
Browse files Browse the repository at this point in the history
Descriptions as strings in GraphQL SDL
  • Loading branch information
Christian Joudrey authored Feb 12, 2018
2 parents 443da22 + 0ba9070 commit af836db
Show file tree
Hide file tree
Showing 21 changed files with 315 additions and 61 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ Options:
schema definition will be read from STDIN instead of specified file
--comment-descriptions
use old way of defining descriptions in GraphQL SDL
-c, --config-direction <path>
path to begin searching for config files
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"cosmiconfig": "^3.1.0",
"figures": "^2.0.0",
"glob": "^7.1.2",
"graphql": "^0.10.1",
"graphql": "^0.13.0",
"graphql-config": "^1.0.0",
"lodash": "^4.17.4"
},
Expand Down
11 changes: 10 additions & 1 deletion src/configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@ export class Configuration {
- schemaPaths: [string array] file(s) to read schema from
- customRulePaths: [string array] path to additional custom rules to be loaded
- stdin: [boolean] pass schema via stdin?
- commentDescriptions: [boolean] use old way of defining descriptions in GraphQL SDL
*/
constructor(options = {}, stdinFd = null) {
const defaultOptions = { format: 'text', customRulePaths: [] };
const defaultOptions = {
format: 'text',
customRulePaths: [],
commentDescriptions: false,
};
const configOptions = loadOptionsFromConfig(options.configDirectory);

// TODO Get configs from .graphqlconfig file
Expand All @@ -33,6 +38,10 @@ export class Configuration {
);
}

getCommentDescriptions() {
return this.options.commentDescriptions;
}

getSchema() {
if (this.schema) {
return this.schema;
Expand Down
8 changes: 6 additions & 2 deletions src/rules/enum_values_have_descriptions.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { getDescription } from 'graphql/utilities/buildASTSchema';
import { ValidationError } from '../validation_error';

export function EnumValuesHaveDescriptions(context) {
export function EnumValuesHaveDescriptions(configuration, context) {
return {
EnumValueDefinition(node, key, parent, path, ancestors) {
if (getDescription(node)) {
if (
getDescription(node, {
commentDescriptions: configuration.getCommentDescriptions(),
})
) {
return;
}

Expand Down
8 changes: 6 additions & 2 deletions src/rules/fields_have_descriptions.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { getDescription } from 'graphql/utilities/buildASTSchema';
import { ValidationError } from '../validation_error';

export function FieldsHaveDescriptions(context) {
export function FieldsHaveDescriptions(configuration, context) {
return {
FieldDefinition(node, key, parent, path, ancestors) {
if (getDescription(node)) {
if (
getDescription(node, {
commentDescriptions: configuration.getCommentDescriptions(),
})
) {
return;
}

Expand Down
8 changes: 6 additions & 2 deletions src/rules/input_object_values_have_descriptions.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { getDescription } from 'graphql/utilities/buildASTSchema';
import { ValidationError } from '../validation_error';

export function InputObjectValuesHaveDescriptions(context) {
export function InputObjectValuesHaveDescriptions(configuration, context) {
return {
InputValueDefinition(node, key, parent, path, ancestors) {
if (getDescription(node)) {
if (
getDescription(node, {
commentDescriptions: configuration.getCommentDescriptions(),
})
) {
return;
}

Expand Down
22 changes: 13 additions & 9 deletions src/rules/types_have_descriptions.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { getDescription } from 'graphql/utilities/buildASTSchema';
import { ValidationError } from '../validation_error';

function validateTypeHasDescription(context, node, typeKind) {
if (getDescription(node)) {
function validateTypeHasDescription(configuration, context, node, typeKind) {
if (
getDescription(node, {
commentDescriptions: configuration.getCommentDescriptions(),
})
) {
return;
}

Expand All @@ -17,34 +21,34 @@ function validateTypeHasDescription(context, node, typeKind) {
);
}

export function TypesHaveDescriptions(context) {
export function TypesHaveDescriptions(configuration, context) {
return {
TypeExtensionDefinition(node) {
return false;
},

ScalarTypeDefinition(node) {
validateTypeHasDescription(context, node, 'scalar');
validateTypeHasDescription(configuration, context, node, 'scalar');
},

ObjectTypeDefinition(node) {
validateTypeHasDescription(context, node, 'object');
validateTypeHasDescription(configuration, context, node, 'object');
},

InterfaceTypeDefinition(node) {
validateTypeHasDescription(context, node, 'interface');
validateTypeHasDescription(configuration, context, node, 'interface');
},

UnionTypeDefinition(node) {
validateTypeHasDescription(context, node, 'union');
validateTypeHasDescription(configuration, context, node, 'union');
},

EnumTypeDefinition(node) {
validateTypeHasDescription(context, node, 'enum');
validateTypeHasDescription(configuration, context, node, 'enum');
},

InputObjectTypeDefinition(node) {
validateTypeHasDescription(context, node, 'input object');
validateTypeHasDescription(configuration, context, node, 'input object');
},
};
}
11 changes: 9 additions & 2 deletions src/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export function run(stdout, stdin, stderr, argv) {
'-p, --custom-rule-paths <paths>',
'path to additional custom rules to be loaded. Example: rules/*.js'
)
.option(
'--comment-descriptions',
'use old way of defining descriptions in GraphQL SDL'
)
// DEPRECATED - This code should be removed in v1.0.0.
.option(
'-o, --only <rules>',
Expand Down Expand Up @@ -84,8 +88,7 @@ export function run(stdout, stdin, stderr, argv) {
const rules = configuration.getRules();
const schemaSourceMap = configuration.getSchemaSourceMap();

const errors = validateSchemaDefinition(schema, rules);

const errors = validateSchemaDefinition(schema, rules, configuration);
const groupedErrors = groupErrorsBySchemaFilePath(errors, schemaSourceMap);

stdout.write(formatter(groupedErrors));
Expand Down Expand Up @@ -137,6 +140,10 @@ function getOptionsFromCommander(commander) {
options.customRulePaths = commander.customRulePaths.split(',');
}

if (commander.commentDescriptions) {
options.commentDescriptions = commander.commentDescriptions;
}

if (commander.args && commander.args.length) {
options.schemaPaths = commander.args;
}
Expand Down
27 changes: 24 additions & 3 deletions src/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { validate } from 'graphql/validation';
import { buildASTSchema } from 'graphql/utilities/buildASTSchema';
import { GraphQLError } from 'graphql/error';

export function validateSchemaDefinition(schemaDefinition, rules) {
export function validateSchemaDefinition(
schemaDefinition,
rules,
configuration
) {
let ast;
try {
ast = parse(schemaDefinition);
Expand All @@ -14,8 +18,15 @@ export function validateSchemaDefinition(schemaDefinition, rules) {
throw e;
}
}
const schema = buildASTSchema(ast);
const errors = validate(schema, ast, rules);
const schema = buildASTSchema(ast, {
commentDescriptions: configuration.getCommentDescriptions(),
});

const rulesWithConfiguration = rules.map(rule => {
return ruleWithConfiguration(rule, configuration);
});

const errors = validate(schema, ast, rulesWithConfiguration);
const sortedErrors = sortErrors(errors);

return sortedErrors;
Expand All @@ -26,3 +37,13 @@ function sortErrors(errors) {
return a.locations[0].line - b.locations[0].line;
});
}

function ruleWithConfiguration(rule, configuration) {
if (rule.length == 2) {
return function(context) {
return rule(configuration, context);
};
} else {
return rule;
}
}
42 changes: 33 additions & 9 deletions test/assertions.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,28 @@ import { parse } from 'graphql';
import { validate } from 'graphql/validation';
import { buildASTSchema } from 'graphql/utilities/buildASTSchema';
import { kebabCase } from 'lodash';
import { validateSchemaDefinition } from '../src/validator.js';
import { Configuration } from '../src/configuration.js';

const DefaultSchema = `
# Query root
"Query root"
type Query {
# Field
"Field"
a: String
}
`;

export function expectFailsRule(rule, schemaSDL, expectedErrors = []) {
const ast = parse(`${schemaSDL}${DefaultSchema}`);
const schema = buildASTSchema(ast);
const errors = validate(schema, ast, [rule]);
return expectFailsRuleWithConfiguration(rule, schemaSDL, {}, expectedErrors);
}

export function expectFailsRuleWithConfiguration(
rule,
schemaSDL,
configurationOptions,
expectedErrors = []
) {
const errors = validateSchemaWithRule(rule, schemaSDL, configurationOptions);

assert(errors.length > 0, "Expected rule to fail but didn't");

Expand All @@ -30,13 +39,28 @@ export function expectFailsRule(rule, schemaSDL, expectedErrors = []) {
);
}

export function expectPassesRule(rule, schemaSDL, expectedErrors = []) {
const ast = parse(`${schemaSDL}${DefaultSchema}`);
const schema = buildASTSchema(ast);
const errors = validate(schema, ast, [rule]);
export function expectPassesRule(rule, schemaSDL) {
expectPassesRuleWithConfiguration(rule, schemaSDL, {});
}

export function expectPassesRuleWithConfiguration(
rule,
schemaSDL,
configurationOptions
) {
const errors = validateSchemaWithRule(rule, schemaSDL, configurationOptions);

assert(
errors.length == 0,
`Expected rule to pass but didn't got these errors:\n\n${errors.join('\n')}`
);
}

function validateSchemaWithRule(rule, schemaSDL, configurationOptions) {
const fullSchemaSDL = `${schemaSDL}${DefaultSchema}`;
const rules = [rule];
const configuration = new Configuration(configurationOptions, null);
const errors = validateSchemaDefinition(fullSchemaSDL, rules, configuration);

return errors;
}
12 changes: 12 additions & 0 deletions test/configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,4 +262,16 @@ extend type Query {
assert.equal(issues.length, 2);
});
});

describe('getCommentDescriptions', () => {
it('defaults to false', () => {
const configuration = new Configuration({});
assert.equal(configuration.getCommentDescriptions(), false);
});

it('returns specified value', () => {
const configuration = new Configuration({ commentDescriptions: true });
assert.equal(configuration.getCommentDescriptions(), true);
});
});
});
18 changes: 10 additions & 8 deletions test/fixtures/animal.graphql
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
# Base query
"Base query"
type Query {
# Animal Viewing
"Animal Viewing"
viewer: Animal!
}

# Animal
"Animal"
type Animal {
# name
"name"
name: String!
# type

"type"
types: [AnimalTypes]
}

# Animal type enum
"Animal type enum"
enum AnimalTypes {
# meow
"meow"
CAT_ENUM
# woof

"woof"
DOG_ENUM
}
7 changes: 7 additions & 0 deletions test/fixtures/schema.comment-descriptions.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Query
type Query {
a: String

# B
b: String
}
4 changes: 2 additions & 2 deletions test/fixtures/valid.graphql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Query
"Query"
type Query {
# a
"a"
a: String!
}
Loading

0 comments on commit af836db

Please sign in to comment.