Skip to content

Commit

Permalink
(introspection) - Add options to include more schema info to minifyIn…
Browse files Browse the repository at this point in the history
…trospectionQuery (#1578)

* Add includeScalars option to minifyIntrospectionQuery

* Remove Any scalar if it's not needed

* Add includeEnums / includeInputs / includeDirectives options

* Update changeset

* Fix linting issues in minifyIntrospectionQuery

* Fix directives mapping for undefined directives input
  • Loading branch information
kitten authored Apr 28, 2021
1 parent d90f7de commit 398007e
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 24 deletions.
7 changes: 7 additions & 0 deletions .changeset/lovely-hounds-tap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@urql/introspection': minor
---

Add options to `@urql/introspection`'s `minifyIntrospectionQuery` allowing the inclusion of more
information into the minified schema as needed, namely `includeScalars`, `includeEnums`,
`includeInputs`, and `includeDirectives`.
122 changes: 98 additions & 24 deletions packages/introspection/src/minifyIntrospectionQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,44 @@ import {
IntrospectionQuery,
IntrospectionType,
IntrospectionTypeRef,
IntrospectionInputValue,
} from 'graphql';

let _includeScalars = false;
let _includeEnums = false;
let _includeInputs = false;
let _hasAnyType = false;

const anyType: IntrospectionTypeRef = {
kind: 'SCALAR',
name: 'Any',
};

const mapType = (
fromType: any,
toType: IntrospectionTypeRef
): IntrospectionTypeRef => {
const mapType = (fromType: any): IntrospectionTypeRef => {
switch (fromType.kind) {
case 'NON_NULL':
case 'LIST':
return {
kind: fromType.kind,
ofType: mapType(fromType.ofType, toType),
ofType: mapType(fromType.ofType),
};

case 'SCALAR':
_hasAnyType = _hasAnyType || _includeScalars;
return _includeScalars ? fromType : anyType;

case 'INPUT_OBJECT':
_hasAnyType = _hasAnyType || _includeInputs;
return _includeInputs ? fromType : anyType;

case 'ENUM':
return toType;
_hasAnyType = _hasAnyType || _includeEnums;
return _includeEnums ? fromType : anyType;

case 'OBJECT':
case 'INTERFACE':
case 'UNION':
return {
kind: fromType.kind,
name: fromType.name,
};
return fromType;

default:
throw new TypeError(
Expand All @@ -45,20 +52,53 @@ const minifyIntrospectionType = (
type: IntrospectionType
): IntrospectionType => {
switch (type.kind) {
case 'OBJECT': {
case 'SCALAR':
return {
kind: 'SCALAR',
name: type.name,
};

case 'ENUM':
return {
kind: 'ENUM',
name: type.name,
enumValues: type.enumValues.map(
value =>
({
name: value.name,
} as any)
),
};

case 'INPUT_OBJECT': {
return {
kind: 'INPUT_OBJECT',
name: type.name,
inputFields: type.inputFields.map(
field =>
({
name: field.name,
type: mapType(field.type),
defaultValue: field.defaultValue || undefined,
} as IntrospectionInputValue)
),
};
}

case 'OBJECT':
return {
kind: 'OBJECT',
name: type.name,
fields: type.fields.map(
field =>
({
name: field.name,
type: field.type && mapType(field.type, anyType),
type: field.type && mapType(field.type),
args:
field.args &&
field.args.map(arg => ({
name: arg.name,
type: mapType(arg.type, anyType),
type: mapType(arg.type),
})),
} as any)
),
Expand All @@ -69,22 +109,21 @@ const minifyIntrospectionType = (
name: int.name,
})),
};
}

case 'INTERFACE': {
case 'INTERFACE':
return {
kind: 'INTERFACE',
name: type.name,
fields: type.fields.map(
field =>
({
name: field.name,
type: field.type && mapType(field.type, anyType),
type: field.type && mapType(field.type),
args:
field.args &&
field.args.map(arg => ({
name: arg.name,
type: mapType(arg.type, anyType),
type: mapType(arg.type),
})),
} as any)
),
Expand All @@ -101,9 +140,8 @@ const minifyIntrospectionType = (
name: type.name,
})),
};
}

case 'UNION': {
case 'UNION':
return {
kind: 'UNION',
name: type.name,
Expand All @@ -112,22 +150,39 @@ const minifyIntrospectionType = (
name: type.name,
})),
};
}

default:
return type;
}
};

export interface MinifySchemaOptions {
/** Includes scalar names (instead of an `Any` replacement) in the output when enabled. */
includeScalars?: boolean;
/** Includes enums (instead of an `Any` replacement) in the output when enabled. */
includeEnums?: boolean;
/** Includes all input objects (instead of an `Any` replacement) in the output when enabled. */
includeInputs?: boolean;
/** Includes all directives in the output when enabled. */
includeDirectives?: boolean;
}

/** Removes extraneous information from introspected schema data to minify it and prepare it for use on the client-side. */
export const minifyIntrospectionQuery = (
schema: IntrospectionQuery
schema: IntrospectionQuery,
opts: MinifySchemaOptions = {}
): IntrospectionQuery => {
if (!schema || !('__schema' in schema)) {
throw new TypeError('Expected to receive an IntrospectionQuery.');
}

_hasAnyType = false;
_includeScalars = !!opts.includeScalars;
_includeEnums = !!opts.includeEnums;
_includeInputs = !!opts.includeInputs;

const {
__schema: { queryType, mutationType, subscriptionType, types },
__schema: { queryType, mutationType, subscriptionType, types, directives },
} = schema;

const minifiedTypes = types
Expand All @@ -144,6 +199,9 @@ export const minifyIntrospectionQuery = (
return false;
default:
return (
(_includeScalars && type.kind === 'SCALAR') ||
(_includeEnums && type.kind === 'ENUM') ||
(_includeInputs && type.kind === 'INPUT_OBJECT') ||
type.kind === 'OBJECT' ||
type.kind === 'INTERFACE' ||
type.kind === 'UNION'
Expand All @@ -152,15 +210,31 @@ export const minifyIntrospectionQuery = (
})
.map(minifyIntrospectionType);

minifiedTypes.push({ kind: 'SCALAR', name: anyType.name });
const minifiedDirectives = (directives || []).map(directive => ({
name: directive.name,
isRepeatable: directive.isRepeatable ? true : undefined,
locations: directive.locations,
args: directive.args.map(
arg =>
({
name: arg.name,
type: mapType(arg.type),
defaultValue: arg.defaultValue || undefined,
} as IntrospectionInputValue)
),
}));

if (!_includeScalars || !_includeEnums || !_includeInputs || _hasAnyType) {
minifiedTypes.push({ kind: 'SCALAR', name: anyType.name });
}

return {
__schema: {
queryType,
mutationType,
subscriptionType,
types: minifiedTypes,
directives: [],
directives: opts.includeDirectives ? minifiedDirectives : [],
},
};
};

0 comments on commit 398007e

Please sign in to comment.