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