"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 };