Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

eslint-plugin-graphql

Package Overview
Dependencies
Maintainers
4
Versions
44
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint-plugin-graphql - npm Package Compare versions

Comparing version 2.1.1 to 3.0.0

.eslintrc.js

14

CHANGELOG.md
# Change log
### vNEXT
### v3.0.0
- BREAKING: The `required-fields` rule has been significantly changed to make it a completely reliable method of ensuring an `id` field (or any other field name) is always requested when available. [PR #199](https://github.com/apollographql/eslint-plugin-graphql/pull/199) Here is the behavior, let's say we are requiring field `id`:
- On any field whose return type defines a field called `id`, the selection set must directly contain `id`.
- In any named fragment declaration whose type defines a field called `id`, the selection set must directly contain `id`.
- An inline fragment whose type defines a field called `id` must contain `id` in its selection set unless its parent is also an inline fragment that contains the field `id`.
- Here's a specific case which is _no longer valid_:
- `query { greetings { hello ... on Greetings { id } } }`
- This must now be written as `query { greetings { id hello ... on Greetings { id } } }`
- This is a more conservative approach than before, driven by the fact that it's quite hard to ensure that a combination of inline fragments actually covers all of the possible types of a selection set.
- Fix breaking change in `graphql@^14.0.0` that renamed `ProvidedNonNullArguments` to `ProvidedRequiredArguments` [#192](https://github.com/apollographql/eslint-plugin-graphql/pull/192)
- Update dependencies to graphql-tools 4 and eslint 5.9 [#193](https://github.com/apollographql/eslint-plugin-graphql/pull/193)
### v2.1.1
- Fix support for InlineFragments with the `required-fields` rule in [#140](https://github.com/apollographql/eslint-plugin-graphql/pull/140/files) by [Steve Hollaar](https://github.com/stevehollaar)
- Fix error location information for literal .graphql files and strings with leading newlines in [#122](https://github.com/apollographql/eslint-plugin-graphql/pull/122) by [Dan Freeman](https://github.com/dfreeman)
- Add [`fraql`](https://github.com/smooth-code/fraql) environment

@@ -8,0 +22,0 @@ ### v2.1.0

272

lib/index.js

@@ -24,6 +24,10 @@ 'use strict';

var _rules = require('./rules');
var _customGraphQLValidationRules = require('./customGraphQLValidationRules');
var customRules = _interopRequireWildcard(_rules);
var customRules = _interopRequireWildcard(_customGraphQLValidationRules);
var _constants = require('./constants');
var _createRule = require('./createRule');
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }

@@ -43,7 +47,11 @@

lokka: (0, _lodash.without)(allGraphQLValidatorNames, 'KnownFragmentNames', 'NoUnusedFragments'),
relay: (0, _lodash.without)(allGraphQLValidatorNames, 'KnownDirectives', 'KnownFragmentNames', 'NoUndefinedVariables', 'NoUnusedFragments', 'ProvidedNonNullArguments', 'ScalarLeafs'),
fraql: (0, _lodash.without)(allGraphQLValidatorNames, 'KnownFragmentNames', 'NoUnusedFragments'),
relay: (0, _lodash.without)(allGraphQLValidatorNames, 'KnownDirectives', 'KnownFragmentNames', 'NoUndefinedVariables', 'NoUnusedFragments',
// `graphql` < 14
'ProvidedNonNullArguments',
// `graphql`@14
'ProvidedRequiredArguments', 'ScalarLeafs'),
literal: (0, _lodash.without)(allGraphQLValidatorNames, 'KnownFragmentNames', 'NoUnusedFragments')
};
var internalTag = 'ESLintPluginGraphQLFile';
var gqlFiles = ['gql', 'graphql'];

@@ -53,3 +61,3 @@

env: {
enum: ['lokka', 'relay', 'apollo', 'literal']
enum: ['lokka', 'fraql', 'relay', 'apollo', 'literal']
},

@@ -72,90 +80,5 @@ schemaJson: {

}
};
function createRule(context, optionParser) {
var tagNames = new Set();
var tagRules = [];
var options = context.options.length === 0 ? [{}] : context.options;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
var _loop = function _loop() {
var optionGroup = _step.value;
var _optionParser = optionParser(optionGroup),
schema = _optionParser.schema,
env = _optionParser.env,
tagName = _optionParser.tagName,
validators = _optionParser.validators;
var boundValidators = validators.map(function (v) {
return function (ctx) {
return v(ctx, optionGroup);
};
});
if (tagNames.has(tagName)) {
throw new Error('Multiple options for GraphQL tag ' + tagName);
}
tagNames.add(tagName);
tagRules.push({ schema: schema, env: env, tagName: tagName, validators: boundValidators });
};
for (var _iterator = options[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
_loop();
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return {
TaggedTemplateExpression: function TaggedTemplateExpression(node) {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = tagRules[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var _ref2 = _step2.value;
var schema = _ref2.schema,
env = _ref2.env,
tagName = _ref2.tagName,
validators = _ref2.validators;
if (templateExpressionMatchesTag(tagName, node)) {
return handleTemplateTag(node, context, schema, env, validators);
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
};
}
// schemaJson, schemaJsonFilepath, schemaString and projectName are mutually exclusive:
var schemaPropsExclusiveness = {
// schemaJson, schemaJsonFilepath, schemaString and projectName are mutually exclusive:
};var schemaPropsExclusiveness = {
oneOf: [{

@@ -201,3 +124,3 @@ required: ['schemaJson'],

create: function create(context) {
return createRule(context, function (optionGroup) {
return (0, _createRule.createRule)(context, function (optionGroup) {
return parseOptions(optionGroup, context);

@@ -218,3 +141,3 @@ });

create: function create(context) {
return createRule(context, function (optionGroup) {
return (0, _createRule.createRule)(context, function (optionGroup) {
return parseOptions(_extends({

@@ -246,3 +169,3 @@ validators: ['OperationsMustHaveNames']

create: function create(context) {
return createRule(context, function (optionGroup) {
return (0, _createRule.createRule)(context, function (optionGroup) {
return parseOptions(_extends({

@@ -266,3 +189,3 @@ validators: ['RequiredFields'],

create: function create(context) {
return createRule(context, function (optionGroup) {
return (0, _createRule.createRule)(context, function (optionGroup) {
return parseOptions(_extends({

@@ -285,3 +208,3 @@ validators: ['typeNamesShouldBeCapitalized']

create: function create(context) {
return createRule(context, function (optionGroup) {
return (0, _createRule.createRule)(context, function (optionGroup) {
return parseOptions(_extends({

@@ -341,4 +264,4 @@ validators: ['noDeprecatedFields']

// Validate env
if (env && env !== 'lokka' && env !== 'relay' && env !== 'apollo' && env !== 'literal') {
throw new Error('Invalid option for env, only `apollo`, `lokka`, `relay`, and `literal` supported.');
if (env && env !== 'lokka' && env !== 'fraql' && env !== 'relay' && env !== 'apollo' && env !== 'literal') {
throw new Error('Invalid option for env, only `apollo`, `lokka`, `fraql`, `relay`, and `literal` supported.');
}

@@ -353,3 +276,3 @@

} else if (env === 'literal') {
tagName = internalTag;
tagName = _constants.internalTag;
} else {

@@ -400,149 +323,2 @@ tagName = 'gql';

function templateExpressionMatchesTag(tagName, node) {
var tagNameSegments = tagName.split('.').length;
if (tagNameSegments === 1) {
// Check for single identifier, like 'gql'
if (node.tag.type !== 'Identifier' || node.tag.name !== tagName) {
return false;
}
} else if (tagNameSegments === 2) {
// Check for dotted identifier, like 'Relay.QL'
if (node.tag.type !== 'MemberExpression' || node.tag.object.name + '.' + node.tag.property.name !== tagName) {
return false;
}
} else {
// We don't currently support 3 segments so ignore
return false;
}
return true;
}
function handleTemplateTag(node, context, schema, env, validators) {
var text = void 0;
try {
text = replaceExpressions(node.quasi, context, env);
} catch (e) {
if (e.message !== 'Invalid interpolation') {
console.log(e);
}
return;
}
// Re-implement syntax sugar for fragment names, which is technically not valid
// graphql
if ((env === 'lokka' || env === 'relay') && /fragment\s+on/.test(text)) {
text = text.replace('fragment', 'fragment _');
}
var ast = void 0;
try {
ast = (0, _graphql.parse)(text);
} catch (error) {
context.report({
node: node,
message: error.message.split('\n')[0],
loc: locFrom(node, error)
});
return;
}
var validationErrors = schema ? (0, _graphql.validate)(schema, ast, validators) : [];
if (validationErrors && validationErrors.length > 0) {
context.report({
node: node,
message: validationErrors[0].message,
loc: locFrom(node, validationErrors[0])
});
return;
}
}
function locFrom(node, error) {
if (!error.locations || !error.locations.length) {
return;
}
var location = error.locations[0];
var line = void 0;
var column = void 0;
if (location.line === 1 && node.tag.name !== internalTag) {
line = node.loc.start.line;
column = node.tag.loc.end.column + location.column;
} else {
line = node.loc.start.line + location.line - 1;
column = location.column - 1;
}
return {
line: line,
column: column
};
}
function replaceExpressions(node, context, env) {
var chunks = [];
node.quasis.forEach(function (element, i) {
var chunk = element.value.cooked;
var value = node.expressions[i];
chunks.push(chunk);
if (!env || env === 'apollo') {
// In Apollo, interpolation is only valid outside top-level structures like `query` or `mutation`.
// We'll check to make sure there's an equivalent set of opening and closing brackets, otherwise
// we're attempting to do an invalid interpolation.
if (chunk.split('{').length - 1 !== chunk.split('}').length - 1) {
context.report({
node: value,
message: 'Invalid interpolation - fragment interpolation must occur outside of the brackets.'
});
throw new Error('Invalid interpolation');
}
}
if (!element.tail) {
// Preserve location of errors by replacing with exactly the same length
var nameLength = value.end - value.start;
if (env === 'relay' && /:\s*$/.test(chunk)) {
// The chunk before this one had a colon at the end, so this
// is a variable
// Add 2 for brackets in the interpolation
var placeholder = strWithLen(nameLength + 2);
chunks.push('$' + placeholder);
} else if (env === 'lokka' && /\.\.\.\s*$/.test(chunk)) {
// This is Lokka-style fragment interpolation where you actually type the '...' yourself
var _placeholder = strWithLen(nameLength + 3);
chunks.push(_placeholder);
} else if (env === 'relay') {
// This is Relay-style fragment interpolation where you don't type '...'
// Ellipsis cancels out extra characters
var _placeholder2 = strWithLen(nameLength);
chunks.push('...' + _placeholder2);
} else if (!env || env === 'apollo') {
// In Apollo, fragment interpolation is only valid outside of brackets
// Since we don't know what we'd interpolate here (that occurs at runtime),
// we're not going to do anything with this interpolation.
} else {
// Invalid interpolation
context.report({
node: value,
message: 'Invalid interpolation - not a valid fragment or variable.'
});
throw new Error('Invalid interpolation');
}
}
});
return chunks.join('');
}
function strWithLen(len) {
// from http://stackoverflow.com/questions/14343844/create-a-string-of-variable-length-filled-with-a-repeated-character
return new Array(len + 1).join('x');
}
var gqlProcessor = {

@@ -560,3 +336,3 @@ preprocess: function preprocess(text) {

var escaped = text.replace(/[`\\]|\$\{/g, '\\$&');
return [internalTag + '`' + escaped + '`'];
return [_constants.internalTag + '`' + escaped + '`'];
},

@@ -563,0 +339,0 @@ postprocess: function postprocess(messages) {

{
"name": "eslint-plugin-graphql",
"version": "2.1.1",
"version": "3.0.0",
"description": "GraphQL ESLint plugin.",

@@ -10,3 +10,5 @@ "author": "Sashko Stubailo",

"prepublish": "babel ./src --ignore test --out-dir ./lib",
"pretest": "node test/updateSchemaJson.js"
"pretest": "node test/updateSchemaJson.js",
"tav": "tav",
"lint": "eslint 'src/**/*.js' 'test/**/*.js'"
},

@@ -19,14 +21,13 @@ "homepage": "https://github.com/apollostack/eslint-plugin-graphql",

"devDependencies": {
"babel": "6.23.0",
"babel-cli": "6.26.0",
"babel-core": "6.26.3",
"babel-eslint": "8.2.3",
"babel-eslint": "10.0.1",
"babel-plugin-transform-runtime": "6.23.0",
"babel-preset-es2015": "6.24.1",
"babel-preset-stage-0": "6.24.1",
"eslint": "4.19.1",
"mocha": "5.1.1",
"graphql": "0.13.2",
"graphql-tools": "3.0.0",
"test-all-versions": "3.3.2"
"eslint": "5.9.0",
"graphql": "14.0.2",
"graphql-tools": "4.0.3",
"mocha": "5.2.0",
"test-all-versions": "3.3.3"
},

@@ -48,4 +49,4 @@ "babel": {

"peerDependencies": {
"graphql": "^0.12.0 || ^0.13.0"
"graphql": "^0.12.0 || ^0.13.0 || ^14.0.0"
}
}

@@ -19,2 +19,3 @@ # eslint-plugin-graphql

3. [Lokka](https://github.com/kadirahq/lokka)
3. [FraQL](https://github.com/smooth-code/fraql)

@@ -35,5 +36,5 @@ If you want to lint your GraphQL schema, rather than queries, check out [cjoudrey/graphql-schema-linter](https://github.com/cjoudrey/graphql-schema-linter).

All of the rules provided by this plugin have a few options in common. There are examples of how to use these with Apollo, Relay, Lokka and literal files further down.
All of the rules provided by this plugin have a few options in common. There are examples of how to use these with Apollo, Relay, Lokka, FraQL and literal files further down.
- `env`: Import default settings for your GraphQL client. Supported values: `'apollo'`, `'relay'`, `'lokka'`, `'literal'`. Defaults to `'apollo'`. This is used for the slight parsing differences in the GraphQL syntax between Apollo, Relay and Lokka, as well as giving nice defaults to some other options.
- `env`: Import default settings for your GraphQL client. Supported values: `'apollo'`, `'relay'`, `'lokka'`, `'fraql'` `'literal'`. Defaults to `'apollo'`. This is used for the slight parsing differences in the GraphQL syntax between Apollo, Relay, Lokka and FraQL as well as giving nice defaults to some other options.

@@ -44,3 +45,3 @@ - `tagName`: The name of the template literal tag that this plugin should look for when searching for GraphQL queries. It has different defaults depending on the `env` option:

- `'internal'`: Special automatic value
- others: `'gql'`
- others: `'gql'`, `'graphql'`

@@ -50,3 +51,3 @@ You also have to specify a schema. You can either do it using _one_ of these options:

- `schemaJson`: Your schema as JSON.
- `schemaJsonFilepath`: The absolute path to your schema as a .json file.
- `schemaJsonFilepath`: The absolute path to your schema as a .json file. (Warning: this variant is incompatible with `eslint --cache`.)
- `schemaString`: Your schema in the Schema Language format as a string.

@@ -103,3 +104,3 @@

// Import default settings for your GraphQL client. Supported values:
// 'apollo', 'relay', 'lokka', 'literal'
// 'apollo', 'relay', 'lokka', 'fraql', 'literal'
env: 'apollo',

@@ -110,3 +111,3 @@

// OR provide absolute path to your schema JSON
// OR provide absolute path to your schema JSON (but not if using `eslint --cache`!)
// schemaJsonFilepath: path.resolve(__dirname, './schema.json'),

@@ -135,3 +136,3 @@

// Import default settings for your GraphQL client. Supported values:
// 'apollo', 'relay', 'lokka', 'literal'
// 'apollo', 'relay', 'lokka', 'fraql', 'literal'
env: 'relay',

@@ -142,3 +143,3 @@

// OR provide absolute path to your schema JSON
// OR provide absolute path to your schema JSON (but not if using `eslint --cache`!)
// schemaJsonFilepath: path.resolve(__dirname, './schema.json'),

@@ -167,3 +168,3 @@

// Import default settings for your GraphQL client. Supported values:
// 'apollo', 'relay', 'lokka', 'literal'
// 'apollo', 'relay', 'lokka', 'fraql', 'literal'
env: 'lokka',

@@ -174,2 +175,33 @@

// OR provide absolute path to your schema JSON (but not if using `eslint --cache`!)
// schemaJsonFilepath: path.resolve(__dirname, './schema.json'),
// OR provide the schema in the Schema Language format
// schemaString: printSchema(schema),
// Optional, the name of the template tag, defaults to 'gql'
tagName: 'gql'
}]
},
plugins: [
'graphql'
]
}
```
### Example config for FraQL
```js
// In a file called .eslintrc.js
module.exports = {
parser: "babel-eslint",
rules: {
"graphql/template-strings": ['error', {
// Import default settings for your GraphQL client. Supported values:
// 'apollo', 'relay', 'lokka', 'fraql', 'literal'
env: 'fraql',
// Import your schema JSON here
schemaJson: require('./schema.json'),
// OR provide absolute path to your schema JSON

@@ -200,3 +232,3 @@ // schemaJsonFilepath: path.resolve(__dirname, './schema.json'),

// Import default settings for your GraphQL client. Supported values:
// 'apollo', 'relay', 'lokka', 'literal'
// 'apollo', 'relay', 'lokka', 'fraql', 'literal'
env: 'literal',

@@ -207,3 +239,3 @@

// OR provide absolute path to your schema JSON
// OR provide absolute path to your schema JSON (but not if using `eslint --cache`!)
// schemaJsonFilepath: path.resolve(__dirname, './schema.json'),

@@ -259,3 +291,3 @@

// Import default settings for your GraphQL client. Supported values:
// 'apollo', 'relay', 'lokka', 'literal'
// 'apollo', 'relay', 'lokka', 'fraql', 'literal'
env: 'literal'

@@ -334,3 +366,3 @@ // no need to specify schema here, it will be automatically determined using .graphqlconfig

- `PossibleFragmentSpreads`
- `ProvidedNonNullArguments` (*disabled by default in `relay`*)
- `ProvidedRequiredArguments` (*disabled by default in `relay`*)
- `ScalarLeafs` (*disabled by default in `relay`*)

@@ -337,0 +369,0 @@ - `SingleFieldSubscriptions`

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc