| "use strict"; |
| |
| Object.defineProperty(exports, "__esModule", { |
| value: true |
| }); |
| exports.processors = exports.rules = undefined; |
| |
| 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 = require("fs"); |
| |
| var _fs2 = _interopRequireDefault(_fs); |
| |
| var _path = require("path"); |
| |
| var _path2 = _interopRequireDefault(_path); |
| |
| var _graphql = require("graphql"); |
| |
| var _lodash = require("lodash"); |
| |
| var _graphqlConfig = require("graphql-config"); |
| |
| var _customGraphQLValidationRules = require("./customGraphQLValidationRules"); |
| |
| 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; } } |
| |
| 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") |
| }; |
| |
| var gqlFiles = ["gql", "graphql"]; |
| |
| var defaultRuleProperties = { |
| env: { |
| enum: ["lokka", "fraql", "relay", "apollo", "literal"] |
| }, |
| schemaJson: { |
| type: "object" |
| }, |
| schemaJsonFilepath: { |
| type: "string" |
| }, |
| schemaString: { |
| type: "string" |
| }, |
| tagName: { |
| type: "string", |
| pattern: "^[$_a-zA-Z$_][a-zA-Z0-9$_]+(\\.[a-zA-Z0-9$_]+)?$" |
| }, |
| projectName: { |
| type: "string" |
| } |
| }; |
| |
| // schemaJson, schemaJsonFilepath, schemaString and projectName are mutually exclusive: |
| var schemaPropsExclusiveness = { |
| oneOf: [{ |
| required: ["schemaJson"], |
| not: { required: ["schemaString", "schemaJsonFilepath", "projectName"] } |
| }, { |
| required: ["schemaJsonFilepath"], |
| not: { required: ["schemaJson", "schemaString", "projectName"] } |
| }, { |
| required: ["schemaString"], |
| not: { required: ["schemaJson", "schemaJsonFilepath", "projectName"] } |
| }, { |
| not: { |
| anyOf: [{ required: ["schemaString"] }, { required: ["schemaJson"] }, { required: ["schemaJsonFilepath"] }] |
| } |
| }] |
| }; |
| |
| var rules = exports.rules = { |
| "template-strings": { |
| meta: { |
| schema: { |
| type: "array", |
| items: _extends({ |
| additionalProperties: false, |
| properties: _extends({}, defaultRuleProperties, { |
| validators: { |
| oneOf: [{ |
| type: "array", |
| uniqueItems: true, |
| items: { |
| enum: allGraphQLValidatorNames |
| } |
| }, { |
| enum: ["all"] |
| }] |
| } |
| }) |
| }, schemaPropsExclusiveness) |
| } |
| }, |
| create: function create(context) { |
| return (0, _createRule.createRule)(context, function (optionGroup) { |
| return parseOptions(optionGroup, context); |
| }); |
| } |
| }, |
| "named-operations": { |
| meta: { |
| schema: { |
| type: "array", |
| items: _extends({ |
| additionalProperties: false, |
| properties: _extends({}, defaultRuleProperties) |
| }, schemaPropsExclusiveness) |
| } |
| }, |
| create: function create(context) { |
| return (0, _createRule.createRule)(context, function (optionGroup) { |
| return parseOptions(_extends({ |
| validators: ["OperationsMustHaveNames"] |
| }, optionGroup), context); |
| }); |
| } |
| }, |
| "required-fields": { |
| meta: { |
| schema: { |
| type: "array", |
| minItems: 1, |
| items: _extends({ |
| additionalProperties: false, |
| properties: _extends({}, defaultRuleProperties, { |
| requiredFields: { |
| type: "array", |
| items: { |
| type: "string" |
| } |
| } |
| }), |
| 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); |
| }); |
| } |
| }, |
| "capitalized-type-name": { |
| meta: { |
| schema: { |
| type: "array", |
| items: _extends({ |
| additionalProperties: false, |
| properties: _extends({}, defaultRuleProperties) |
| }, schemaPropsExclusiveness) |
| } |
| }, |
| create: function create(context) { |
| return (0, _createRule.createRule)(context, function (optionGroup) { |
| return parseOptions(_extends({ |
| validators: ["typeNamesShouldBeCapitalized"] |
| }, optionGroup), context); |
| }); |
| } |
| }, |
| "no-deprecated-fields": { |
| meta: { |
| schema: { |
| type: "array", |
| items: _extends({ |
| additionalProperties: false, |
| properties: _extends({}, defaultRuleProperties) |
| }, schemaPropsExclusiveness) |
| } |
| }, |
| create: function create(context) { |
| return (0, _createRule.createRule)(context, function (optionGroup) { |
| return parseOptions(_extends({ |
| validators: ["noDeprecatedFields"] |
| }, optionGroup), context); |
| }); |
| } |
| } |
| }; |
| |
| 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; |
| |
| |
| var cacheHit = schemaCache[JSON.stringify(optionGroup)]; |
| if (cacheHit && env !== "literal") { |
| return cacheHit; |
| } |
| |
| // Validate and unpack schema |
| var schema = void 0; |
| if (schemaJson) { |
| schema = initSchema(schemaJson); |
| } else if (schemaJsonFilepath) { |
| schema = initSchemaFromFile(schemaJsonFilepath); |
| } else if (schemaString) { |
| schema = initSchemaFromString(schemaString); |
| } else { |
| try { |
| var config = (0, _graphqlConfig.getGraphQLConfig)(_path2.default.dirname(context.getFilename())); |
| var projectConfig = void 0; |
| if (projectName) { |
| projectConfig = config.getProjects()[projectName]; |
| if (!projectConfig) { |
| throw new Error("Project with name \"" + projectName + "\" not found in " + config.configPath + "."); |
| } |
| } else { |
| projectConfig = config.getConfigForFile(context.getFilename()); |
| } |
| if (projectConfig) { |
| var key = config.configPath + "[" + projectConfig.projectName + "]"; |
| schema = projectCache[key]; |
| if (!schema) { |
| schema = projectConfig.getSchema(); |
| projectCache[key] = schema; |
| } |
| } |
| if (cacheHit) { |
| return _extends({}, cacheHit, { schema: 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 e; |
| } |
| } |
| |
| // 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 |
| var tagName = void 0; |
| if (tagNameOption) { |
| tagName = tagNameOption; |
| } else if (env === "relay") { |
| tagName = "Relay.QL"; |
| } else if (env === "literal") { |
| tagName = _constants.internalTag; |
| } else { |
| tagName = "gql"; |
| } |
| |
| // 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; |
| if (validatorNamesOption === "all") { |
| validatorNames = allGraphQLValidatorNames; |
| } else if (validatorNamesOption) { |
| validatorNames = validatorNamesOption; |
| } else { |
| validatorNames = envGraphQLValidatorNames[env] || allGraphQLValidatorNames; |
| } |
| |
| var validators = validatorNames.map(function (name) { |
| if (name in customRules) { |
| return customRules[name]; |
| } else { |
| return require("graphql/validation/rules/" + name)[name]; |
| } |
| }); |
| var results = { schema: schema, env: env, tagName: tagName, validators: validators }; |
| schemaCache[JSON.stringify(optionGroup)] = results; |
| return results; |
| } |
| |
| function initSchema(json) { |
| var 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); |
| } |
| |
| function initSchemaFromFile(jsonFile) { |
| return initSchema(JSON.parse(_fs2.default.readFileSync(jsonFile, "utf8"))); |
| } |
| |
| function initSchemaFromString(source) { |
| return (0, _graphql.buildSchema)(source); |
| } |
| |
| var gqlProcessor = { |
| preprocess: function preprocess(text) { |
| // Wrap the text in backticks and prepend the internal tag. First the text |
| // must be escaped, because of the three sequences that have special |
| // meaning in JavaScript template literals, and could change the meaning of |
| // the text or cause syntax errors. |
| // https://tc39.github.io/ecma262/#prod-TemplateCharacter |
| // |
| // - "`" would end the template literal. |
| // - "\" would start an escape sequence. |
| // - "${" would start an interpolation. |
| var escaped = text.replace(/[`\\]|\$\{/g, "\\$&"); |
| return [_constants.internalTag + "`" + escaped + "`"]; |
| }, |
| postprocess: function postprocess(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); |
| }); |
| } |
| }; |
| |
| var processors = exports.processors = (0, _lodash.reduce)(gqlFiles, function (result, value) { |
| return _extends({}, result, _defineProperty({}, "." + value, gqlProcessor)); |
| }, {}); |
| |
| exports.default = { |
| rules: rules, |
| processors: processors |
| }; |