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 3.1.1 to 4.0.0

.babelrc.js

9

CHANGELOG.md

@@ -5,2 +5,11 @@ # Change log

- _Nothing yet!_
### v4.0.0
- Improve identity template literal tag docs. [PR #254](https://github.com/apollographql/eslint-plugin-graphql/pull/254) by [Jayden Seric](https://github.com/jaydenseric).
- Add support for GraphQL 15. [PR #271](https://github.com/apollographql/eslint-plugin-graphql/pull/271) by [Scott Taylor](https://github.com/staylor).
- Update all `devDependencies` - upgrades the project to use Babel 7 and ESLint 6. [PR #271](https://github.com/apollographql/eslint-plugin-graphql/pull/271) by [Scott Taylor](https://github.com/staylor).
- **BREAKING**: Minimum supported Node.js version is now Node.js 10; Dropped support for Node.js 8. [PR #271](https://github.com/apollographql/eslint-plugin-graphql/pull/271) by [Scott Taylor](https://github.com/staylor).
### v3.1.1

@@ -7,0 +16,0 @@

4

lib/constants.js

@@ -6,2 +6,4 @@ "use strict";

});
var internalTag = exports.internalTag = "ESLintPluginGraphQLFile";
exports.internalTag = void 0;
const internalTag = "ESLintPluginGraphQLFile";
exports.internalTag = internalTag;

@@ -18,8 +18,6 @@ "use strict";

function replaceExpressions(node, context, env) {
var chunks = [];
node.quasis.forEach(function (element, i) {
var chunk = element.value.cooked;
var value = node.expressions[i];
const chunks = [];
node.quasis.forEach((element, i) => {
const chunk = element.value.cooked;
const value = node.expressions[i];
chunks.push(chunk);

@@ -42,3 +40,3 @@

// Preserve location of errors by replacing with exactly the same length
var nameLength = value.end - value.start;
const nameLength = value.end - value.start;

@@ -48,17 +46,15 @@ if (env === "relay" && /:\s*$/.test(chunk)) {

// is a variable
// Add 2 for brackets in the interpolation
var placeholder = strWithLen(nameLength + 2);
const 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);
const 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
const placeholder = strWithLen(nameLength);
chunks.push("..." + placeholder);
} 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),

@@ -80,3 +76,2 @@ // we're not going to do anything with this interpolation.

});
return chunks.join("");

@@ -89,6 +84,7 @@ }

}
var location = error.locations[0];
var line = void 0;
var column = void 0;
const location = error.locations[0];
let line;
let column;
if (location.line === 1 && node.tag.name !== _constants.internalTag) {

@@ -103,4 +99,4 @@ line = node.loc.start.line;

return {
line: line,
column: column
line,
column
};

@@ -110,3 +106,4 @@ }

function handleTemplateTag(node, context, schema, env, validators) {
var text = void 0;
let text;
try {

@@ -118,12 +115,13 @@ text = replaceExpressions(node.quasi, context, env);

}
return;
}
} // Re-implement syntax sugar for fragment names, which is technically not valid
// graphql
// Re-implement syntax sugar for fragment names, which is technically not valid
// graphql
if ((env === "lokka" || env === "relay" || env === "fraql") && /fragment\s+on/.test(text)) {
text = text.replace("fragment", "fragment _");
text = text.replace("fragment", `fragment _`);
}
var ast = void 0;
let ast;

@@ -134,3 +132,3 @@ try {

context.report({
node: node,
node,
message: error.message.split("\n")[0],

@@ -142,6 +140,7 @@ loc: locFrom(node, error)

var validationErrors = schema ? (0, _graphql.validate)(schema, ast, validators) : [];
const validationErrors = schema ? (0, _graphql.validate)(schema, ast, validators) : [];
if (validationErrors && validationErrors.length > 0) {
context.report({
node: node,
node,
message: validationErrors[0].message,

@@ -155,3 +154,4 @@ loc: locFrom(node, validationErrors[0])

function templateExpressionMatchesTag(tagName, node) {
var tagNameSegments = tagName.split(".").length;
const tagNameSegments = tagName.split(".").length;
if (tagNameSegments === 1) {

@@ -171,2 +171,3 @@ // Check for single identifier, like 'gql'

}
return true;

@@ -176,83 +177,43 @@ }

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;
const tagNames = new Set();
const tagRules = [];
const options = context.options.length === 0 ? [{}] : context.options;
try {
var _loop = function _loop() {
var optionGroup = _step.value;
for (const optionGroup of options) {
const {
schema,
env,
tagName,
validators
} = optionParser(optionGroup);
const boundValidators = validators.map(v => ctx => v(ctx, optionGroup));
var _optionParser = optionParser(optionGroup),
schema = _optionParser.schema,
env = _optionParser.env,
tagName = _optionParser.tagName,
validators = _optionParser.validators;
if (tagNames.has(tagName)) {
throw new Error("Multiple options for GraphQL tag " + tagName);
}
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;
}
}
tagNames.add(tagName);
tagRules.push({
schema,
env,
tagName,
validators: boundValidators
});
}
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);
}
TaggedTemplateExpression(node) {
for (const {
schema,
env,
tagName,
validators
} of tagRules) {
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;
}
}
}
}
};
}

@@ -13,7 +13,5 @@ "use strict";

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
function OperationsMustHaveNames(context) {
return {
OperationDefinition: function OperationDefinition(node) {
OperationDefinition(node) {
if (!node.name) {

@@ -23,2 +21,3 @@ context.reportError(new _graphql.GraphQLError("All operations must be named", [node]));

}
};

@@ -28,3 +27,3 @@ }

function getFieldWasRequestedOnNode(node, field) {
return node.selectionSet.selections.some(function (n) {
return node.selectionSet.selections.some(n => {
return n.kind === "Field" && n.name.value === field;

@@ -43,14 +42,15 @@ });

function RequiredFields(context, options) {
var requiredFields = options.requiredFields;
const {
requiredFields
} = options;
return {
FragmentDefinition: function FragmentDefinition(node) {
requiredFields.forEach(function (field) {
var type = context.getType();
FragmentDefinition(node) {
requiredFields.forEach(field => {
const type = context.getType();
if (fieldAvailableOnType(type, field)) {
var fieldWasRequested = getFieldWasRequestedOnNode(node, field);
const fieldWasRequested = getFieldWasRequestedOnNode(node, field);
if (!fieldWasRequested) {
context.reportError(new _graphql.GraphQLError("'" + field + "' field required on 'fragment " + node.name.value + " on " + node.typeCondition.name.value + "'", [node]));
context.reportError(new _graphql.GraphQLError(`'${field}' field required on 'fragment ${node.name.value} on ${node.typeCondition.name.value}'`, [node]));
}

@@ -61,8 +61,7 @@ }

// Every inline fragment must have the required field specified inside
// itself or in some parent selection set.
InlineFragment: function InlineFragment(node, key, parent, path, ancestors) {
requiredFields.forEach(function (field) {
var type = context.getType();
InlineFragment(node, key, parent, path, ancestors) {
requiredFields.forEach(field => {
const type = context.getType();

@@ -75,8 +74,6 @@ if (fieldAvailableOnType(type, field)) {

var ancestorClone = [].concat(_toConsumableArray(ancestors));
const ancestorClone = [...ancestors];
let nearestFieldOrExecutableDefinition;
let nextAncestor; // Now, walk up the ancestors, until you see a field or executable definition.
var nearestFieldOrExecutableDefinition = void 0;
var nextAncestor = void 0;
// Now, walk up the ancestors, until you see a field or executable definition.
while (!nearestFieldOrExecutableDefinition) {

@@ -92,12 +89,12 @@ nextAncestor = ancestorClone.pop();

}
}
} // If we never found a field or executable definition, the query is malformed
// If we never found a field or executable definition, the query is malformed
if (!nearestFieldOrExecutableDefinition) {
throw new Error("Inline fragment found inside document without a parent field, fragment definition, or operation definition.");
}
} // We found a field or executable definition, but we never saw the field we were looking for in
// the intermediate selection sets.
// We found a field or executable definition, but we never saw the field we were looking for in
// the intermediate selection sets.
context.reportError(new _graphql.GraphQLError("'" + field + "' field required on '... on " + node.typeCondition.name.value + "'", [node]));
context.reportError(new _graphql.GraphQLError(`'${field}' field required on '... on ${node.typeCondition.name.value}'`, [node]));
}

@@ -107,8 +104,8 @@ });

// Every field that can have the field directly on it, should. It's not
// enough to have some child fragment to include the field, since we don't
// know if that fragment covers all of the possible type options.
Field: function Field(node) {
var def = context.getFieldDef();
Field(node) {
const def = context.getFieldDef();
if (!def) {

@@ -118,7 +115,8 @@ return;

requiredFields.forEach(function (field) {
requiredFields.forEach(field => {
if (fieldAvailableOnType(def.type, field)) {
var fieldWasRequested = getFieldWasRequestedOnNode(node, field);
const fieldWasRequested = getFieldWasRequestedOnNode(node, field);
if (!fieldWasRequested) {
context.reportError(new _graphql.GraphQLError("'" + field + "' field required on '" + node.name.value + "'", [node]));
context.reportError(new _graphql.GraphQLError(`'${field}' field required on '${node.name.value}'`, [node]));
}

@@ -128,2 +126,3 @@ }

}
};

@@ -134,4 +133,5 @@ }

return {
NamedType: function NamedType(node) {
var typeName = node.name.value;
NamedType(node) {
const typeName = node.name.value;
if (typeName[0] == typeName[0].toLowerCase()) {

@@ -141,25 +141,31 @@ context.reportError(new _graphql.GraphQLError("All type names should start with a capital letter", [node]));

}
};
}
} // Mostly taken from https://github.com/graphql/graphql-js/blob/063148de039b02670a760b8d3dfaf2a04a467169/src/utilities/findDeprecatedUsages.js
// See explanation in [#93](https://github.com/apollographql/eslint-plugin-graphql/pull/93)
// Mostly taken from https://github.com/graphql/graphql-js/blob/063148de039b02670a760b8d3dfaf2a04a467169/src/utilities/findDeprecatedUsages.js
// See explanation in [#93](https://github.com/apollographql/eslint-plugin-graphql/pull/93)
function noDeprecatedFields(context) {
return {
Field: function Field(node) {
var fieldDef = context.getFieldDef();
Field(node) {
const fieldDef = context.getFieldDef();
if (fieldDef && fieldDef.isDeprecated) {
var parentType = context.getParentType();
const parentType = context.getParentType();
if (parentType) {
var reason = fieldDef.deprecationReason;
context.reportError(new _graphql.GraphQLError("The field " + parentType.name + "." + fieldDef.name + " is deprecated." + (reason ? " " + reason : ""), [node]));
const reason = fieldDef.deprecationReason;
context.reportError(new _graphql.GraphQLError(`The field ${parentType.name}.${fieldDef.name} is deprecated.` + (reason ? " " + reason : ""), [node]));
}
}
},
EnumValue: function EnumValue(node) {
EnumValue(node) {
// context is of type ValidationContext which doesn't export getEnumValue.
// Bypass the public API to grab that information directly from _typeInfo.
var enumVal = context._typeInfo.getEnumValue();
const enumVal = context._typeInfo.getEnumValue();
if (enumVal && enumVal.isDeprecated) {
var type = (0, _graphql.getNamedType)(context.getInputType());
const type = (0, _graphql.getNamedType)(context.getInputType());
if (!type) {

@@ -169,7 +175,8 @@ return;

var reason = enumVal.deprecationReason;
context.reportError(new _graphql.GraphQLError("The enum value " + type.name + "." + enumVal.name + " is deprecated." + (reason ? " " + reason : ""), [node]));
const reason = enumVal.deprecationReason;
context.reportError(new _graphql.GraphQLError(`The enum value ${type.name}.${enumVal.name} is deprecated.` + (reason ? " " + reason : ""), [node]));
}
}
};
}
"use strict";
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.processors = exports.rules = undefined;
exports.default = exports.processors = exports.rules = void 0;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _fs = _interopRequireDefault(require("fs"));
var _fs = require("fs");
var _path = _interopRequireDefault(require("path"));
var _fs2 = _interopRequireDefault(_fs);
var _graphql = require("graphql");
var _path = require("path");
var _lodash = _interopRequireDefault(require("lodash.flatten"));
var _path2 = _interopRequireDefault(_path);
var _lodash2 = _interopRequireDefault(require("lodash.without"));
var _graphql = require("graphql");
var _lodash = require("lodash");
var _graphqlConfig = require("graphql-config");
var _customGraphQLValidationRules = require("./customGraphQLValidationRules");
var customRules = _interopRequireWildcard(require("./customGraphQLValidationRules"));
var customRules = _interopRequireWildcard(_customGraphQLValidationRules);
var _constants = require("./constants");

@@ -32,28 +30,22 @@

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; } }
const allGraphQLValidatorNames = _graphql.specifiedRules.map(rule => rule.name); // Map of env name to list of rule names.
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var allGraphQLValidatorNames = _graphql.specifiedRules.map(function (rule) {
return rule.name;
});
// Map of env name to list of rule names.
var envGraphQLValidatorNames = {
apollo: (0, _lodash.without)(allGraphQLValidatorNames, "KnownFragmentNames", "NoUnusedFragments"),
lokka: (0, _lodash.without)(allGraphQLValidatorNames, "KnownFragmentNames", "NoUnusedFragments"),
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")
const envGraphQLValidatorNames = {
apollo: (0, _lodash2.default)(allGraphQLValidatorNames, "KnownFragmentNames", "NoUnusedFragments", // `graphql`@15
"KnownFragmentNamesRule", "NoUnusedFragmentsRule"),
lokka: (0, _lodash2.default)(allGraphQLValidatorNames, "KnownFragmentNames", "NoUnusedFragments", // `graphql`@15
"KnownFragmentNamesRule", "NoUnusedFragmentsRule"),
fraql: (0, _lodash2.default)(allGraphQLValidatorNames, "KnownFragmentNames", "NoUnusedFragments", // `graphql`@15
"KnownFragmentNamesRule", "NoUnusedFragmentsRule"),
relay: (0, _lodash2.default)(allGraphQLValidatorNames, "KnownDirectives", "KnownFragmentNames", "NoUndefinedVariables", "NoUnusedFragments", // `graphql`@15
"KnownDirectivesRule", "KnownFragmentNamesRule", "NoUndefinedVariablesRule", "NoUnusedFragmentsRule", // `graphql` < 14
"ProvidedNonNullArguments", // `graphql`@14
"ProvidedRequiredArguments", "ScalarLeafs", // `graphql`@15
"ProvidedRequiredArgumentsRule", "ScalarLeafsRule"),
literal: (0, _lodash2.default)(allGraphQLValidatorNames, "KnownFragmentNames", "NoUnusedFragments", // `graphql`@15
"KnownFragmentNamesRule", "NoUnusedFragmentsRule")
};
var gqlFiles = ["gql", "graphql"];
var defaultRuleProperties = {
const gqlFiles = ["gql", "graphql"];
const defaultRuleProperties = {
env: {

@@ -78,23 +70,33 @@ enum: ["lokka", "fraql", "relay", "apollo", "literal"]

}
};
}; // schemaJson, schemaJsonFilepath, schemaString and projectName are mutually exclusive:
// schemaJson, schemaJsonFilepath, schemaString and projectName are mutually exclusive:
var schemaPropsExclusiveness = {
const schemaPropsExclusiveness = {
oneOf: [{
required: ["schemaJson"],
not: { required: ["schemaString", "schemaJsonFilepath", "projectName"] }
not: {
required: ["schemaString", "schemaJsonFilepath", "projectName"]
}
}, {
required: ["schemaJsonFilepath"],
not: { required: ["schemaJson", "schemaString", "projectName"] }
not: {
required: ["schemaJson", "schemaString", "projectName"]
}
}, {
required: ["schemaString"],
not: { required: ["schemaJson", "schemaJsonFilepath", "projectName"] }
not: {
required: ["schemaJson", "schemaJsonFilepath", "projectName"]
}
}, {
not: {
anyOf: [{ required: ["schemaString"] }, { required: ["schemaJson"] }, { required: ["schemaJsonFilepath"] }]
anyOf: [{
required: ["schemaString"]
}, {
required: ["schemaJson"]
}, {
required: ["schemaJsonFilepath"]
}]
}
}]
};
var rules = exports.rules = {
const rules = {
"template-strings": {

@@ -104,5 +106,5 @@ meta: {

type: "array",
items: _extends({
items: {
additionalProperties: false,
properties: _extends({}, defaultRuleProperties, {
properties: { ...defaultRuleProperties,
validators: {

@@ -119,11 +121,8 @@ oneOf: [{

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

@@ -134,14 +133,15 @@ "named-operations": {

type: "array",
items: _extends({
items: {
additionalProperties: false,
properties: _extends({}, defaultRuleProperties)
}, schemaPropsExclusiveness)
properties: { ...defaultRuleProperties
},
...schemaPropsExclusiveness
}
}
},
create: function create(context) {
return (0, _createRule.createRule)(context, function (optionGroup) {
return parseOptions(_extends({
validators: ["OperationsMustHaveNames"]
}, optionGroup), context);
});
create: context => {
return (0, _createRule.createRule)(context, optionGroup => parseOptions({
validators: ["OperationsMustHaveNames"],
...optionGroup
}, context));
}

@@ -154,5 +154,5 @@ },

minItems: 1,
items: _extends({
items: {
additionalProperties: false,
properties: _extends({}, defaultRuleProperties, {
properties: { ...defaultRuleProperties,
requiredFields: {

@@ -164,14 +164,16 @@ type: "array",

}
}),
required: ["requiredFields"]
}, schemaPropsExclusiveness)
},
required: ["requiredFields"],
...schemaPropsExclusiveness
}
}
},
create: function create(context) {
return (0, _createRule.createRule)(context, function (optionGroup) {
return parseOptions(_extends({
validators: ["RequiredFields"],
options: { requiredFields: optionGroup.requiredFields }
}, optionGroup), context);
});
create: context => {
return (0, _createRule.createRule)(context, optionGroup => parseOptions({
validators: ["RequiredFields"],
options: {
requiredFields: optionGroup.requiredFields
},
...optionGroup
}, context));
}

@@ -183,14 +185,15 @@ },

type: "array",
items: _extends({
items: {
additionalProperties: false,
properties: _extends({}, defaultRuleProperties)
}, schemaPropsExclusiveness)
properties: { ...defaultRuleProperties
},
...schemaPropsExclusiveness
}
}
},
create: function create(context) {
return (0, _createRule.createRule)(context, function (optionGroup) {
return parseOptions(_extends({
validators: ["typeNamesShouldBeCapitalized"]
}, optionGroup), context);
});
create: context => {
return (0, _createRule.createRule)(context, optionGroup => parseOptions({
validators: ["typeNamesShouldBeCapitalized"],
...optionGroup
}, context));
}

@@ -202,38 +205,44 @@ },

type: "array",
items: _extends({
items: {
additionalProperties: false,
properties: _extends({}, defaultRuleProperties)
}, schemaPropsExclusiveness)
properties: { ...defaultRuleProperties
},
...schemaPropsExclusiveness
}
}
},
create: function create(context) {
return (0, _createRule.createRule)(context, function (optionGroup) {
return parseOptions(_extends({
validators: ["noDeprecatedFields"]
}, optionGroup), context);
});
create: context => {
return (0, _createRule.createRule)(context, optionGroup => parseOptions({
validators: ["noDeprecatedFields"],
...optionGroup
}, context));
}
}
};
exports.rules = rules;
const schemaCache = {};
const projectCache = {};
var schemaCache = {};
var projectCache = {};
function parseOptions(optionGroup, context) {
var schemaJson = optionGroup.schemaJson,
schemaJsonFilepath = optionGroup.schemaJsonFilepath,
schemaString = optionGroup.schemaString,
env = optionGroup.env,
projectName = optionGroup.projectName,
tagNameOption = optionGroup.tagName,
validatorNamesOption = optionGroup.validators;
const {
schemaJson,
// Schema via JSON object
schemaJsonFilepath,
// Or Schema via absolute filepath
schemaString,
// Or Schema as string,
env,
projectName,
tagName: tagNameOption,
validators: validatorNamesOption
} = optionGroup;
const cacheHit = schemaCache[JSON.stringify(optionGroup)];
var cacheHit = schemaCache[JSON.stringify(optionGroup)];
if (cacheHit && env !== "literal") {
return cacheHit;
}
} // Validate and unpack schema
// Validate and unpack schema
var schema = void 0;
let schema;
if (schemaJson) {

@@ -247,38 +256,55 @@ schema = initSchema(schemaJson);

try {
var config = (0, _graphqlConfig.getGraphQLConfig)(_path2.default.dirname(context.getFilename()));
var projectConfig = void 0;
const config = (0, _graphqlConfig.loadConfigSync)({
rootDir: _path.default.resolve(process.cwd(), _path.default.dirname(context.getFilename()))
});
let projectConfig;
if (projectName) {
projectConfig = config.getProjects()[projectName];
projectConfig = config.getProject(projectName);
if (!projectConfig) {
throw new Error("Project with name \"" + projectName + "\" not found in " + config.configPath + ".");
throw new Error(`Project with name "${projectName}" not found in ${config.filepath}.`);
}
} else {
projectConfig = config.getConfigForFile(context.getFilename());
try {
projectConfig = config.getProjectForFile(context.getFilename());
} catch (e) {
if (!(e instanceof _graphqlConfig.ProjectNotFoundError)) {
throw e;
}
}
}
if (projectConfig) {
var key = config.configPath + "[" + projectConfig.projectName + "]";
const key = `${config.filepath}[${projectConfig.name}]`;
schema = projectCache[key];
if (!schema) {
schema = projectConfig.getSchema();
schema = projectConfig.getSchemaSync();
projectCache[key] = schema;
}
}
if (cacheHit) {
return _extends({}, cacheHit, { schema: schema });
return { ...cacheHit,
schema
};
}
} catch (e) {
if (e instanceof _graphqlConfig.ConfigNotFoundError) {
throw new Error("Must provide .graphqlconfig file or pass in `schemaJson` option " + "with schema object or `schemaJsonFilepath` with absolute path to the json file.");
throw new Error("Must provide GraphQL Config file or pass in `schemaJson` option " + "with schema object or `schemaJsonFilepath` with absolute path to the json file.");
}
throw e;
}
}
} // Validate env
// Validate env
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.");
}
} // Validate tagName and set default
// Validate tagName and set default
var tagName = void 0;
let tagName;
if (tagNameOption) {

@@ -292,9 +318,10 @@ tagName = tagNameOption;

tagName = "gql";
}
// The validator list may be:
} // The validator list may be:
// The string 'all' to use all rules.
// An array of rule names.
// null/undefined to use the default rule set of the environment, or all rules.
var validatorNames = void 0;
let validatorNames;
if (validatorNamesOption === "all") {

@@ -308,10 +335,15 @@ validatorNames = allGraphQLValidatorNames;

var validators = validatorNames.map(function (name) {
const validators = validatorNames.map(name => {
if (name in customRules) {
return customRules[name];
} else {
return require("graphql/validation/rules/" + name)[name];
return require(`graphql/validation/rules/${name}`)[name];
}
});
var results = { schema: schema, env: env, tagName: tagName, validators: validators };
const results = {
schema,
env,
tagName,
validators
};
schemaCache[JSON.stringify(optionGroup)] = results;

@@ -322,6 +354,8 @@ return results;

function initSchema(json) {
var unpackedSchemaJson = json.data ? json.data : json;
const unpackedSchemaJson = json.data ? json.data : json;
if (!unpackedSchemaJson.__schema) {
throw new Error("Please pass a valid GraphQL introspection query result.");
}
return (0, _graphql.buildClientSchema)(unpackedSchemaJson);

@@ -331,3 +365,3 @@ }

function initSchemaFromFile(jsonFile) {
return initSchema(JSON.parse(_fs2.default.readFileSync(jsonFile, "utf8")));
return initSchema(JSON.parse(_fs.default.readFileSync(jsonFile, "utf8")));
}

@@ -339,4 +373,4 @@

var gqlProcessor = {
preprocess: function preprocess(text) {
const gqlProcessor = {
preprocess: function (text) {
// Wrap the text in backticks and prepend the internal tag. First the text

@@ -351,22 +385,20 @@ // must be escaped, because of the three sequences that have special

// - "${" would start an interpolation.
var escaped = text.replace(/[`\\]|\$\{/g, "\\$&");
return [_constants.internalTag + "`" + escaped + "`"];
const escaped = text.replace(/[`\\]|\$\{/g, "\\$&");
return [`${_constants.internalTag}\`${escaped}\``];
},
postprocess: function postprocess(messages) {
postprocess: function (messages) {
// only report graphql-errors
return (0, _lodash.flatten)(messages).filter(function (message) {
return (0, _lodash.includes)((0, _lodash.keys)(rules).map(function (key) {
return "graphql/" + key;
}), message.ruleId);
});
return (0, _lodash.default)(messages).filter(message => Object.keys(rules).map(key => `graphql/${key}`).includes(message.ruleId));
}
};
var processors = exports.processors = (0, _lodash.reduce)(gqlFiles, function (result, value) {
return _extends({}, result, _defineProperty({}, "." + value, gqlProcessor));
const processors = gqlFiles.reduce((result, value) => {
return { ...result,
[`.${value}`]: gqlProcessor
};
}, {});
exports.default = {
rules: rules,
processors: processors
};
exports.processors = processors;
var _default = {
rules,
processors
};
exports.default = _default;
{
"name": "eslint-plugin-graphql",
"version": "3.1.1",
"version": "4.0.0",
"description": "GraphQL ESLint plugin.",

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

"prepublish": "babel ./src --ignore test --out-dir ./lib",
"pretest": "node test/updateSchemaJson.js",
"pretest": "babel-node test/updateSchemaJson.js",
"tav": "tav",

@@ -21,21 +21,15 @@ "lint": "eslint 'src/**/*.js' 'test/**/*.js'"

"devDependencies": {
"babel-cli": "6.26.0",
"babel-core": "6.26.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": "5.16.0",
"graphql": "14.4.2",
"graphql-tools": "4.0.5",
"mocha": "6.2.0",
"pretty-quick": "1.11.1",
"@babel/cli": "7.10.1",
"@babel/core": "7.10.1",
"@babel/node": "7.10.1",
"@babel/plugin-transform-runtime": "7.10.1",
"@babel/preset-env": "7.10.1",
"@babel/register": "7.9.0",
"babel-eslint": "10.1.0",
"eslint": "6.8.0",
"graphql": "15.0.0",
"mocha": "7.2.0",
"pretty-quick": "2.0.1",
"test-all-versions": "4.1.1"
},
"babel": {
"presets": [
"es2015",
"stage-0"
]
},
"husky": {

@@ -47,12 +41,15 @@ "hooks": {

"engines": {
"node": ">=6.0"
"node": ">=10.0"
},
"browserslist": "node 10",
"license": "MIT",
"dependencies": {
"graphql-config": "^2.0.1",
"lodash": "^4.11.1"
"@babel/runtime": "^7.10.0",
"graphql-config": "^3.0.2",
"lodash.flatten": "^4.4.0",
"lodash.without": "^4.4.0"
},
"peerDependencies": {
"graphql": "^0.12.0 || ^0.13.0 || ^14.0.0"
"graphql": "^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0"
}
}

@@ -59,25 +59,18 @@ # eslint-plugin-graphql

This plugin relies on GraphQL queries being prefixed with a special tag. In Relay and Apollo, this is always done, but other clients often take query strings without a tag. In this case, you can define an identity tag that doesn't do anything except for tell the linter this is a GraphQL query:
This plugin relies on GraphQL queries being prefixed with a special tag. In Relay and Apollo this is done often, but some other clients take query strings without a tag. In this case, [`fake-tag`](https://npm.im/fake-tag) can be used to define an identity tag that doesn't do anything except for tell the linter this is a GraphQL query:
```js
global.gql = (literals, ...substitutions) => {
let result = "";
import gql from "fake-tag";
// run the loop only for the substitution count
for (let i = 0; i < substitutions.length; i++) {
result += literals[i];
result += substitutions[i];
const QUERY_VIEWER_NAME = gql`
query ViewerName {
viewer {
name
}
// add the last literal
result += literals[literals.length - 1];
return result;
}
}
`;
```
Code snippet taken from: <https://leanpub.com/understandinges6/read#leanpub-auto-multiline-strings>
Fake tags won’t be necessary [once `/* GraphQL */` comment tags are supported](https://github.com/apollographql/eslint-plugin-graphql/issues/224).
Note: The linter rule could be extended to identify calls to various specific APIs to eliminate the need for a template literal tag, but this might just make the implementation a lot more complex for little benefit.
### GraphQL literal files

@@ -84,0 +77,0 @@

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