Skip to content

Commit

Permalink
Validate: Unique variable names
Browse files Browse the repository at this point in the history
  • Loading branch information
jjergus committed Feb 18, 2016
1 parent 9234c6d commit 089caad
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
47 changes: 47 additions & 0 deletions src/validation/__tests__/UniqueVariableNames.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright (c) 2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

import { describe, it } from 'mocha';
import { expectPassesRule, expectFailsRule } from './harness';
import {
UniqueVariableNames,
duplicateVariableMessage,
} from '../rules/UniqueVariableNames';


function duplicateVariable(name, l1, c1, l2, c2) {
return {
message: duplicateVariableMessage(name),
locations: [ { line: l1, column: c1 }, { line: l2, column: c2 } ],
};
}

describe('Validate: Unique variable names', () => {

it('unique variable names', () => {
expectPassesRule(UniqueVariableNames, `
query A($x: Int, $y: String) { __typename }
query B($x: String, $y: Int) { __typename }
`);
});

it('duplicate variable names', () => {
expectFailsRule(UniqueVariableNames, `
query A($x: Int, $x: Int, $x: String) { __typename }
query B($x: String, $x: Int) { __typename }
query C($x: Int, $x: Int) { __typename }
`, [
duplicateVariable('x', 2, 16, 2, 25),
duplicateVariable('x', 2, 16, 2, 34),
duplicateVariable('x', 3, 16, 3, 28),
duplicateVariable('x', 4, 16, 4, 25)
]);
});

});
43 changes: 43 additions & 0 deletions src/validation/rules/UniqueVariableNames.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* @flow */
/**
* Copyright (c) 2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

import type { ValidationContext } from '../index';
import type { VariableDefinition } from '../../language/ast';
import { GraphQLError } from '../../error';


export function duplicateVariableMessage(variableName: string): string {
return `There can be only one variable named "${variableName}".`;
}

/**
* Unique variable names
*
* A GraphQL operation is only valid if all its variables are uniquely named.
*/
export function UniqueVariableNames(context: ValidationContext): any {
let knownVariableNames = Object.create(null);
return {
OperationDefinition() {
knownVariableNames = Object.create(null);
},
VariableDefinition(node: VariableDefinition) {
const variableName = node.variable.name.value;
if (knownVariableNames[variableName]) {
context.reportError(new GraphQLError(
duplicateVariableMessage(variableName),
[ knownVariableNames[variableName], node.variable.name ]
));
} else {
knownVariableNames[variableName] = node.variable.name;
}
}
};
}
4 changes: 4 additions & 0 deletions src/validation/specifiedRules.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ import { PossibleFragmentSpreads } from './rules/PossibleFragmentSpreads';
// Spec Section: "Fragments must not form cycles"
import { NoFragmentCycles } from './rules/NoFragmentCycles';

// Spec Section: "Variable Uniqueness"
import { UniqueVariableNames } from './rules/UniqueVariableNames';

// Spec Section: "All Variable Used Defined"
import { NoUndefinedVariables } from './rules/NoUndefinedVariables';

Expand Down Expand Up @@ -97,6 +100,7 @@ export const specifiedRules: Array<(context: ValidationContext) => any> = [
NoUnusedFragments,
PossibleFragmentSpreads,
NoFragmentCycles,
UniqueVariableNames,
NoUndefinedVariables,
NoUnusedVariables,
KnownDirectives,
Expand Down

0 comments on commit 089caad

Please sign in to comment.