UNPKG

graphile-build

Version:

Build a GraphQL schema from plugins

741 lines (723 loc) 34.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = makeNewBuild; var graphql = _interopRequireWildcard(require("graphql")); var _graphqlParseResolveInfo = require("graphql-parse-resolve-info"); var _debug = _interopRequireDefault(require("debug")); var _pluralize = _interopRequireDefault(require("pluralize")); var _lru = _interopRequireDefault(require("@graphile/lru")); var _semver = _interopRequireDefault(require("semver")); var _utils = require("./utils"); var _swallowError = _interopRequireDefault(require("./swallowError")); var _resolveNode = _interopRequireDefault(require("./resolveNode")); var _Live = require("./Live"); var _extend = _interopRequireWildcard(require("./extend")); var _chalk = _interopRequireDefault(require("chalk")); var _crypto = require("crypto"); var _package = require("../package.json"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } let recurseDataGeneratorsForFieldWarned = false; const isString = str => typeof str === "string"; const isDev = ["test", "development"].indexOf(process.env.NODE_ENV) >= 0; const debug = (0, _debug.default)("graphile-build"); /* * This should be more than enough for normal usage. If you come under a * sophisticated attack then the attacker can empty this of useful values (with * a lot of work) but because we use SHA1 hashes under the covers the aliases * will still be consistent even after the LRU cache is exhausted. And SHA1 can * produce half a million hashes per second on my machine, the LRU only gives * us a 10x speedup! */ const hashCache = new _lru.default({ maxLength: 100000 }); /* * This function must never return a string longer than 56 characters. * * This function must only output alphanumeric and underscore characters. * * Collisions in SHA1 aren't problematic here (for us; they will be problematic * for the user deliberately causing them, but that's their own fault!), so * we'll happily take the performance boost over SHA256. */ function hashFieldAlias(str) { const precomputed = hashCache.get(str); if (precomputed) return precomputed; const hash = (0, _crypto.createHash)("sha1").update(str).digest("hex"); hashCache.set(str, hash); return hash; } /* * This function may be replaced at any time, but all versions of it will * always return a representation of `alias` (a valid GraphQL identifier) * that: * * 1. won't conflict with normal GraphQL field names * 2. won't be over 60 characters long (allows for systems with alias length limits, such as PG) * 3. will give the same value when called multiple times within the same GraphQL query * 4. matches the regex /^[@!-_A-Za-z0-9]+$/ * 5. will not be prefixed with `__` (as that will conflict with other Graphile internals) * * It does not guarantee that this alias will be human readable! */ function getSafeAliasFromAlias(alias) { if (alias.length <= 60 && !alias.startsWith("@")) { // Use the `@` to prevent conflicting with normal GraphQL field names, but otherwise let it through verbatim. return `@${alias}`; } else if (alias.length > 1024) { throw new Error(`GraphQL alias '${alias}' is too long, use shorter aliases (max length 1024).`); } else { return `@@${hashFieldAlias(alias)}`; } } /* * This provides a "safe" version of the alias from ResolveInfo, guaranteed to * never be longer than 60 characters. This makes it suitable as a PostgreSQL * identifier. */ function getSafeAliasFromResolveInfo(resolveInfo) { const alias = (0, _graphqlParseResolveInfo.getAliasFromResolveInfo)(resolveInfo); return getSafeAliasFromAlias(alias); } function getNameFromType(Type) { if (Type instanceof GraphQLSchema) { return "schema"; } else { return Type.name; } } const { GraphQLSchema, GraphQLInterfaceType, GraphQLObjectType, GraphQLInputObjectType, GraphQLEnumType, GraphQLUnionType, getNamedType, isCompositeType, isAbstractType } = graphql; const mergeData = (data, gen, ReturnType, arg) => { const results = ensureArray(gen(arg, ReturnType, data)); if (!results) { return; } for (let resultIndex = 0, resultCount = results.length; resultIndex < resultCount; resultIndex++) { const result = results[resultIndex]; const keys = Object.keys(result); for (let i = 0, l = keys.length; i < l; i++) { const k = keys[i]; data[k] = data[k] || []; const value = result[k]; const newData = ensureArray(value); if (newData) { data[k].push(...newData); } } } }; const knownTypes = [GraphQLSchema, GraphQLObjectType, GraphQLInputObjectType, GraphQLEnumType, GraphQLUnionType]; const knownTypeNames = knownTypes.map(k => k.name); function ensureArray(val) { if (val == null) { return; } else if (Array.isArray(val)) { // $FlowFixMe return val; } else { return [val]; } } // eslint-disable-next-line no-unused-vars let ensureName = _fn => {}; if (["development", "test"].indexOf(process.env.NODE_ENV) >= 0) { ensureName = fn => { // $FlowFixMe: displayName if (isDev && !fn.displayName && !fn.name && debug.enabled) { // eslint-disable-next-line no-console console.trace("WARNING: you've added a function with no name as an argDataGenerator, doing so may make debugging more challenging"); } }; } function makeNewBuild(builder) { const allTypes = { Int: graphql.GraphQLInt, Float: graphql.GraphQLFloat, String: graphql.GraphQLString, Boolean: graphql.GraphQLBoolean, ID: graphql.GraphQLID }; const allTypesSources = { Int: "GraphQL Built-in", Float: "GraphQL Built-in", String: "GraphQL Built-in", Boolean: "GraphQL Built-in", ID: "GraphQL Built-in" }; // Every object type gets fieldData associated with each of its // fields. // When a field is defined, it may add to this field data. // When something resolves referencing this type, the resolver may // request the fieldData, e.g. to perform optimisations. // fieldData is an object whose keys are the fields on this // GraphQLObjectType and whose values are an object (whose keys are // arbitrary namespaced keys and whose values are arrays of // information of this kind) const fieldDataGeneratorsByFieldNameByType = new Map(); const fieldArgDataGeneratorsByFieldNameByType = new Map(); return { options: builder.options, graphileBuildVersion: _package.version, versions: { graphql: require("graphql/package.json").version, "graphile-build": _package.version }, hasVersion(packageName, range, options = { includePrerelease: true }) { const packageVersion = this.versions[packageName]; if (!packageVersion) return false; return _semver.default.satisfies(packageVersion, range, options); }, graphql, parseResolveInfo: _graphqlParseResolveInfo.parseResolveInfo, simplifyParsedResolveInfoFragmentWithType: _graphqlParseResolveInfo.simplifyParsedResolveInfoFragmentWithType, getSafeAliasFromAlias, getAliasFromResolveInfo: getSafeAliasFromResolveInfo, // DEPRECATED: do not use this! getSafeAliasFromResolveInfo, resolveAlias(data, _args, _context, resolveInfo) { const alias = getSafeAliasFromResolveInfo(resolveInfo); return data[alias]; }, addType(type, origin) { if (!type.name) { throw new Error(`addType must only be called with named types, try using require('graphql').getNamedType`); } const newTypeSource = origin || ( // 'this' is typically only available after the build is finalized this ? `'addType' call during hook '${this.status.currentHookName}'` : null); if (allTypes[type.name]) { if (allTypes[type.name] !== type) { const oldTypeSource = allTypesSources[type.name]; const firstEntityDetails = !oldTypeSource ? "The first type was registered from an unknown origin." : `The first entity was:\n\n${(0, _extend.indent)(_chalk.default.magenta(oldTypeSource))}`; const secondEntityDetails = !newTypeSource ? "The second type was registered from an unknown origin." : `The second entity was:\n\n${(0, _extend.indent)(_chalk.default.yellow(newTypeSource))}`; throw new Error(`A type naming conflict has occurred - two entities have tried to define the same type '${_chalk.default.bold(type.name)}'.\n\n${(0, _extend.indent)(firstEntityDetails)}\n\n${(0, _extend.indent)(secondEntityDetails)}`); } } else { allTypes[type.name] = type; allTypesSources[type.name] = newTypeSource; } }, getTypeByName(typeName) { return allTypes[typeName]; }, extend: _extend.default, newWithHooks(Type, spec, inScope, performNonEmptyFieldsCheck = false) { const scope = inScope || {}; if (!inScope) { // eslint-disable-next-line no-console console.warn(`No scope was provided to new ${Type.name}[name=${spec.name}], it's highly recommended that you add a scope so other hooks can easily reference your object - please check usage of 'newWithHooks'. To mute this message, just pass an empty object.`); } if (!Type) { throw new Error("No type specified!"); } if (!this.newWithHooks) { throw new Error("Please do not generate the schema during the build building phase, use 'init' instead"); } const fieldDataGeneratorsByFieldName = {}; const fieldArgDataGeneratorsByFieldName = {}; let newSpec = spec; if (knownTypes.indexOf(Type) === -1 && knownTypeNames.indexOf(Type.name) >= 0) { throw new Error(`GraphQL conflict for '${Type.name}' detected! Multiple versions of graphql exist in your node_modules?`); } if (Type === GraphQLSchema) { newSpec = builder.applyHooks(this, "GraphQLSchema", newSpec, { type: "GraphQLSchema", scope }); } else if (Type === GraphQLObjectType) { const addDataGeneratorForField = (fieldName, fn) => { // $FlowFixMe: displayName fn.displayName = // $FlowFixMe: displayName fn.displayName || `${getNameFromType(Self)}:${fieldName}[${fn.name || "anonymous"}]`; fieldDataGeneratorsByFieldName[fieldName] = fieldDataGeneratorsByFieldName[fieldName] || []; fieldDataGeneratorsByFieldName[fieldName].push(fn); }; const recurseDataGeneratorsForField = (fieldName, iKnowWhatIAmDoing) => { /* * Recursing data generators is not safe in general; however there * are certain exceptions - for example when you know there are no * "dynamic" data generator fields - e.g. where the GraphQL alias is * not used at all. In PostGraphile the only case of this is the * PageInfo object as none of the fields accept arguments, and they * do not rely on the GraphQL query alias to store the result. */ if (!iKnowWhatIAmDoing && !recurseDataGeneratorsForFieldWarned) { recurseDataGeneratorsForFieldWarned = true; // eslint-disable-next-line no-console console.error("Use of `recurseDataGeneratorsForField` is NOT SAFE. e.g. `{n1: node { a: field1 }, n2: node { a: field2 } }` cannot resolve correctly."); } const fn = (parsedResolveInfoFragment, ReturnType, ...rest) => { const { args } = parsedResolveInfoFragment; const { fields } = this.simplifyParsedResolveInfoFragmentWithType(parsedResolveInfoFragment, ReturnType); const results = []; const StrippedType = getNamedType(ReturnType); const fieldDataGeneratorsByFieldName = fieldDataGeneratorsByFieldNameByType.get(StrippedType); const argDataGeneratorsForSelfByFieldName = fieldArgDataGeneratorsByFieldNameByType.get(Self); if (argDataGeneratorsForSelfByFieldName) { const argDataGenerators = argDataGeneratorsForSelfByFieldName[fieldName]; for (let genIndex = 0, genCount = argDataGenerators.length; genIndex < genCount; genIndex++) { const gen = argDataGenerators[genIndex]; const local = ensureArray(gen(args, ReturnType, ...rest)); if (local) { results.push(...local); } } } if (fieldDataGeneratorsByFieldName && isCompositeType(StrippedType) && !isAbstractType(StrippedType)) { const typeFields = StrippedType.getFields(); const keys = Object.keys(fields); for (let keyIndex = 0, keyCount = keys.length; keyIndex < keyCount; keyIndex++) { const alias = keys[keyIndex]; const field = fields[alias]; // Run generators with `field` as the `parsedResolveInfoFragment`, pushing results to `results` const gens = fieldDataGeneratorsByFieldName[field.name]; if (gens) { for (let genIndex = 0, genCount = gens.length; genIndex < genCount; genIndex++) { const gen = gens[genIndex]; const local = ensureArray(gen(field, typeFields[field.name].type, ...rest)); if (local) { results.push(...local); } } } } } return results; }; fn.displayName = `recurseDataGeneratorsForField(${getNameFromType(Self)}:${fieldName})`; addDataGeneratorForField(fieldName, fn); // get type from field, get }; const commonContext = { type: "GraphQLObjectType", scope }; newSpec = builder.applyHooks(this, "GraphQLObjectType", newSpec, { ...commonContext, addDataGeneratorForField, recurseDataGeneratorsForField }, `|${newSpec.name}`); const rawSpec = newSpec; newSpec = { ...newSpec, interfaces: () => { const interfacesContext = { ...commonContext, Self, GraphQLObjectType: rawSpec }; let rawInterfaces = rawSpec.interfaces || []; if (typeof rawInterfaces === "function") { rawInterfaces = rawInterfaces(interfacesContext); } return builder.applyHooks(this, "GraphQLObjectType:interfaces", rawInterfaces, interfacesContext, `|${getNameFromType(Self)}`); }, fields: () => { const processedFields = []; const fieldsContext = { ...commonContext, addDataGeneratorForField, recurseDataGeneratorsForField, Self, GraphQLObjectType: rawSpec, fieldWithHooks: (fieldName, spec, fieldScope) => { if (!isString(fieldName)) { throw new Error("It looks like you forgot to pass the fieldName to `fieldWithHooks`, we're sorry this is currently necessary."); } if (!fieldScope) { throw new Error("All calls to `fieldWithHooks` must specify a `fieldScope` " + "argument that gives additional context about the field so " + "that further plugins may more easily understand the field. " + "Keys within this object should contain the phrase 'field' " + "since they will be merged into the parent objects scope and " + "are not allowed to clash. If you really have no additional " + "information to give, please just pass `{}`."); } const argDataGenerators = []; fieldArgDataGeneratorsByFieldName[fieldName] = argDataGenerators; let newSpec = spec; const context = { ...commonContext, Self, addDataGenerator(fn) { return addDataGeneratorForField(fieldName, fn); }, addArgDataGenerator(fn) { ensureName(fn); argDataGenerators.push(fn); }, getDataFromParsedResolveInfoFragment: (parsedResolveInfoFragment, ReturnType) => { const Type = getNamedType(ReturnType); const data = {}; const { fields, args } = this.simplifyParsedResolveInfoFragmentWithType(parsedResolveInfoFragment, ReturnType); // Args -> argDataGenerators for (let dgIndex = 0, dgCount = argDataGenerators.length; dgIndex < dgCount; dgIndex++) { const gen = argDataGenerators[dgIndex]; try { mergeData(data, gen, ReturnType, args); } catch (e) { debug("Failed to execute argDataGenerator '%s' on %s of %s", gen.displayName || gen.name || "anonymous", fieldName, getNameFromType(Self)); throw e; } } // finalSpec.type -> fieldData if (!finalSpec) { throw new Error("It's too early to call this! Call from within resolve"); } const fieldDataGeneratorsByFieldName = fieldDataGeneratorsByFieldNameByType.get(Type); if (fieldDataGeneratorsByFieldName && isCompositeType(Type) && !isAbstractType(Type)) { const typeFields = Type.getFields(); const keys = Object.keys(fields); for (let keyIndex = 0, keyCount = keys.length; keyIndex < keyCount; keyIndex++) { const alias = keys[keyIndex]; const field = fields[alias]; const gens = fieldDataGeneratorsByFieldName[field.name]; if (gens) { const FieldReturnType = typeFields[field.name].type; for (let i = 0, l = gens.length; i < l; i++) { mergeData(data, gens[i], FieldReturnType, field); } } } } return data; }, scope: (0, _extend.default)((0, _extend.default)({ ...scope }, { fieldName }, `Within context for GraphQLObjectType '${rawSpec.name}'`), fieldScope, `Extending scope for field '${fieldName}' within context for GraphQLObjectType '${rawSpec.name}'`) }; if (typeof newSpec === "function") { newSpec = newSpec(context); } newSpec = builder.applyHooks(this, "GraphQLObjectType:fields:field", newSpec, context, `|${getNameFromType(Self)}.fields.${fieldName}`); newSpec.args = newSpec.args || {}; newSpec = { ...newSpec, args: builder.applyHooks(this, "GraphQLObjectType:fields:field:args", newSpec.args, { ...context, field: newSpec, returnType: newSpec.type }, `|${getNameFromType(Self)}.fields.${fieldName}`) }; const finalSpec = newSpec; processedFields.push(finalSpec); return finalSpec; } }; let rawFields = rawSpec.fields || {}; if (typeof rawFields === "function") { rawFields = rawFields(fieldsContext); } const fieldsSpec = builder.applyHooks(this, "GraphQLObjectType:fields", this.extend({}, rawFields, `Default field included in newWithHooks call for '${rawSpec.name}'. ${inScope.__origin || ""}`), fieldsContext, `|${rawSpec.name}`); // Finally, check through all the fields that they've all been processed; any that have not we should do so now. for (const fieldName in fieldsSpec) { const fieldSpec = fieldsSpec[fieldName]; if (processedFields.indexOf(fieldSpec) < 0) { // We've not processed this yet; process it now! fieldsSpec[fieldName] = fieldsContext.fieldWithHooks(fieldName, fieldSpec, { autoField: true // We don't have any additional information }); } } return fieldsSpec; } }; } else if (Type === GraphQLInputObjectType) { const commonContext = { type: "GraphQLInputObjectType", scope }; newSpec = builder.applyHooks(this, "GraphQLInputObjectType", newSpec, commonContext, `|${newSpec.name}`); newSpec.fields = newSpec.fields || {}; const rawSpec = newSpec; newSpec = { ...newSpec, fields: () => { const processedFields = []; const fieldsContext = { ...commonContext, Self, GraphQLInputObjectType: rawSpec, fieldWithHooks: (fieldName, spec, fieldScope = {}) => { if (!isString(fieldName)) { throw new Error("It looks like you forgot to pass the fieldName to `fieldWithHooks`, we're sorry this is currently necessary."); } const context = { ...commonContext, Self, scope: (0, _extend.default)((0, _extend.default)({ ...scope }, { fieldName }, `Within context for GraphQLInputObjectType '${rawSpec.name}'`), fieldScope, `Extending scope for field '${fieldName}' within context for GraphQLInputObjectType '${rawSpec.name}'`) }; let newSpec = spec; if (typeof newSpec === "function") { newSpec = newSpec(context); } newSpec = builder.applyHooks(this, "GraphQLInputObjectType:fields:field", newSpec, context, `|${getNameFromType(Self)}.fields.${fieldName}`); const finalSpec = newSpec; processedFields.push(finalSpec); return finalSpec; } }; let rawFields = rawSpec.fields; if (typeof rawFields === "function") { rawFields = rawFields(fieldsContext); } const fieldsSpec = builder.applyHooks(this, "GraphQLInputObjectType:fields", this.extend({}, rawFields, `Default field included in newWithHooks call for '${rawSpec.name}'. ${inScope.__origin || ""}`), fieldsContext, `|${getNameFromType(Self)}`); // Finally, check through all the fields that they've all been processed; any that have not we should do so now. for (const fieldName in fieldsSpec) { const fieldSpec = fieldsSpec[fieldName]; if (processedFields.indexOf(fieldSpec) < 0) { // We've not processed this yet; process it now! fieldsSpec[fieldName] = fieldsContext.fieldWithHooks(fieldName, fieldSpec, { autoField: true // We don't have any additional information }); } } return fieldsSpec; } }; } else if (Type === GraphQLEnumType) { const commonContext = { type: "GraphQLEnumType", scope }; newSpec = builder.applyHooks(this, "GraphQLEnumType", newSpec, commonContext, `|${newSpec.name}`); newSpec.values = builder.applyHooks(this, "GraphQLEnumType:values", newSpec.values, commonContext, `|${newSpec.name}`); const values = newSpec.values; newSpec.values = Object.keys(values).reduce((memo, valueKey) => { const value = values[valueKey]; const newValue = builder.applyHooks(this, "GraphQLEnumType:values:value", value, commonContext, `|${newSpec.name}|${valueKey}`); memo[valueKey] = newValue; return memo; }, {}); } else if (Type === GraphQLUnionType) { const commonContext = { type: "GraphQLUnionType", scope }; newSpec = builder.applyHooks(this, "GraphQLUnionType", newSpec, { ...commonContext }, `|${newSpec.name}`); const rawSpec = newSpec; newSpec = { ...newSpec, types: () => { const typesContext = { ...commonContext, Self, GraphQLUnionType: rawSpec }; let rawTypes = rawSpec.types || []; if (typeof rawTypes === "function") { rawTypes = rawTypes(typesContext); } return builder.applyHooks(this, "GraphQLUnionType:types", rawTypes, typesContext, `|${getNameFromType(Self)}`); } }; } else if (Type === GraphQLInterfaceType) { const commonContext = { type: "GraphQLInterfaceType", scope }; newSpec = builder.applyHooks(this, "GraphQLInterfaceType", newSpec, commonContext, `|${newSpec.name}`); const rawSpec = newSpec; newSpec = { ...newSpec, fields: () => { const processedFields = []; const fieldsContext = { ...commonContext, Self, GraphQLInterfaceType: rawSpec, fieldWithHooks: (fieldName, spec, fieldScope) => { if (!isString(fieldName)) { throw new Error("It looks like you forgot to pass the fieldName to `fieldWithHooks`, we're sorry this is currently necessary."); } if (!fieldScope) { throw new Error("All calls to `fieldWithHooks` must specify a `fieldScope` " + "argument that gives additional context about the field so " + "that further plugins may more easily understand the field. " + "Keys within this object should contain the phrase 'field' " + "since they will be merged into the parent objects scope and " + "are not allowed to clash. If you really have no additional " + "information to give, please just pass `{}`."); } let newSpec = spec; const context = { ...commonContext, Self, scope: (0, _extend.default)((0, _extend.default)({ ...scope }, { fieldName }, `Within context for GraphQLInterfaceType '${rawSpec.name}'`), fieldScope, `Extending scope for field '${fieldName}' within context for GraphQLInterfaceType '${rawSpec.name}'`) }; if (typeof newSpec === "function") { newSpec = newSpec(context); } newSpec = builder.applyHooks(this, "GraphQLInterfaceType:fields:field", newSpec, context, `|${getNameFromType(Self)}.fields.${fieldName}`); newSpec.args = newSpec.args || {}; newSpec = { ...newSpec, args: builder.applyHooks(this, "GraphQLInterfaceType:fields:field:args", newSpec.args, { ...context, field: newSpec, returnType: newSpec.type }, `|${getNameFromType(Self)}.fields.${fieldName}`) }; const finalSpec = newSpec; processedFields.push(finalSpec); return finalSpec; } }; let rawFields = rawSpec.fields || {}; if (typeof rawFields === "function") { rawFields = rawFields(fieldsContext); } const fieldsSpec = builder.applyHooks(this, "GraphQLInterfaceType:fields", this.extend({}, rawFields, `Default field included in newWithHooks call for '${rawSpec.name}'. ${inScope.__origin || ""}`), fieldsContext, `|${rawSpec.name}`); // Finally, check through all the fields that they've all been processed; any that have not we should do so now. for (const fieldName in fieldsSpec) { const fieldSpec = fieldsSpec[fieldName]; if (processedFields.indexOf(fieldSpec) < 0) { // We've not processed this yet; process it now! fieldsSpec[fieldName] = fieldsContext.fieldWithHooks(fieldName, fieldSpec, { autoField: true // We don't have any additional information }); } } return fieldsSpec; } }; } const finalSpec = newSpec; const Self = new Type(finalSpec); if (!(Self instanceof GraphQLSchema) && performNonEmptyFieldsCheck) { try { if (Self instanceof GraphQLInterfaceType || Self instanceof GraphQLObjectType || Self instanceof GraphQLInputObjectType) { const _Self = Self; if (typeof _Self.getFields === "function") { const fields = _Self.getFields(); if (Object.keys(fields).length === 0) { // We require there's at least one field on GraphQLObjectType and GraphQLInputObjectType records return null; } } } } catch (e) { // This is the error we're expecting to handle: // https://github.com/graphql/graphql-js/blob/831598ba76f015078ecb6c5c1fbaf133302f3f8e/src/type/definition.js#L526-L531 if (inScope && inScope.isRootQuery) { throw e; } const isProbablyAnEmptyObjectError = !!e.message.match(/function which returns such an object/); if (!isProbablyAnEmptyObjectError) { this.swallowError(e); } return null; } } this.scopeByType.set(Self, scope); if (finalSpec.name) { this.addType(Self, scope.__origin || (this ? `'newWithHooks' call during hook '${this.status.currentHookName}'` : null)); } fieldDataGeneratorsByFieldNameByType.set(Self, fieldDataGeneratorsByFieldName); fieldArgDataGeneratorsByFieldNameByType.set(Self, fieldArgDataGeneratorsByFieldName); return Self; }, fieldDataGeneratorsByType: fieldDataGeneratorsByFieldNameByType, // @deprecated fieldDataGeneratorsByFieldNameByType, fieldArgDataGeneratorsByFieldNameByType, inflection: { pluralize: _pluralize.default, singularize: _pluralize.default.singular, upperCamelCase: _utils.upperCamelCase, camelCase: _utils.camelCase, constantCase: _utils.constantCase, // Built-in names (allows you to override these in the output schema) builtin: name => { /* * e.g.: * * graphile-build: * * - Query * - Mutation * - Subscription * - Node * - PageInfo * * graphile-build-pg: * * - Interval * - BigInt * - BigFloat * - BitString * - Point * - Date * - Datetime * - Time * - JSON * - UUID * - InternetAddress * * Other plugins may add their own builtins too; try and avoid conflicts! */ return name; }, // When converting a query field to a subscription (live query) field, this allows you to rename it live: name => name, // Try and make something a valid GraphQL 'Name' coerceToGraphQLName: name => { let resultingName = name; /* * Name is defined in GraphQL to match this regexp: * * /^[_A-Za-z][_0-9A-Za-z]*$/ * * See: https://graphql.github.io/graphql-spec/June2018/#sec-Appendix-Grammar-Summary.Lexical-Tokens * * So if our 'name' starts with a digit, we must prefix it with * something. We'll just use an underscore. */ if (resultingName.match(/^[0-9]/)) { resultingName = "_" + resultingName; } /* * Fields beginning with two underscores are reserved by the GraphQL * introspection systems, trim to just one. */ resultingName = resultingName.replace(/^__+/g, "_"); return resultingName; } }, wrapDescription: _utils.wrapDescription, swallowError: _swallowError.default, // resolveNode: EXPERIMENTAL, API might change! resolveNode: _resolveNode.default, status: { currentHookName: null, currentHookEvent: null }, liveCoordinator: new _Live.LiveCoordinator(), scopeByType: new Map() }; } //# sourceMappingURL=makeNewBuild.js.map