Created
December 4, 2017 17:52
-
-
Save adambom/946eb112da9f79282f3368db9005a8a8 to your computer and use it in GitHub Desktop.
Place these files into the same directory
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var __extends = (this && this.__extends) || (function () { | |
var extendStatics = Object.setPrototypeOf || | |
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | |
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | |
return function (d, b) { | |
extendStatics(d, b); | |
function __() { this.constructor = d; } | |
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | |
}; | |
})(); | |
var __assign = (this && this.__assign) || Object.assign || function(t) { | |
for (var s, i = 1, n = arguments.length; i < n; i++) { | |
s = arguments[i]; | |
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | |
t[p] = s[p]; | |
} | |
return t; | |
}; | |
import { Component, createElement } from 'react'; | |
import * as PropTypes from 'prop-types'; | |
import shallowEqual from './shallowEqual'; | |
var invariant = require('invariant'); | |
var assign = require('object-assign'); | |
var pick = require('lodash.pick'); | |
var hoistNonReactStatics = require('hoist-non-react-statics'); | |
import { parser, DocumentType } from './parser'; | |
var defaultMapPropsToOptions = function () { return ({}); }; | |
var defaultMapResultToProps = function (props) { return props; }; | |
var defaultMapPropsToSkip = function () { return false; }; | |
function observableQueryFields(observable) { | |
var fields = pick(observable, 'variables', 'refetch', 'fetchMore', 'updateQuery', 'startPolling', 'stopPolling', 'subscribeToMore'); | |
Object.keys(fields).forEach(function (key) { | |
if (typeof fields[key] === 'function') { | |
fields[key] = fields[key].bind(observable); | |
} | |
}); | |
return fields; | |
} | |
function getDisplayName(WrappedComponent) { | |
return WrappedComponent.displayName || WrappedComponent.name || 'Component'; | |
} | |
var nextVersion = 0; | |
export default function graphql(document, operationOptions) { | |
if (operationOptions === void 0) { operationOptions = {}; } | |
var _a = operationOptions.options, options = _a === void 0 ? defaultMapPropsToOptions : _a, _b = operationOptions.skip, skip = _b === void 0 ? defaultMapPropsToSkip : _b, _c = operationOptions.alias, alias = _c === void 0 ? 'Apollo' : _c; | |
var mapPropsToOptions = options; | |
if (typeof mapPropsToOptions !== 'function') | |
mapPropsToOptions = function () { return options; }; | |
var mapPropsToSkip = skip; | |
if (typeof mapPropsToSkip !== 'function') | |
mapPropsToSkip = function () { return skip; }; | |
var mapResultToProps = operationOptions.props; | |
var operation = parser(document); | |
var version = nextVersion++; | |
function wrapWithApolloComponent(WrappedComponent) { | |
var graphQLDisplayName = alias + "(" + getDisplayName(WrappedComponent) + ")"; | |
var GraphQL = (function (_super) { | |
__extends(GraphQL, _super); | |
function GraphQL(props, context) { | |
var _this = _super.call(this, props, context) || this; | |
_this.previousData = {}; | |
_this.version = version; | |
_this.type = operation.type; | |
_this.dataForChildViaMutation = _this.dataForChildViaMutation.bind(_this); | |
_this.setWrappedInstance = _this.setWrappedInstance.bind(_this); | |
return _this; | |
} | |
GraphQL.prototype.componentWillMount = function () { | |
if (!this.shouldSkip(this.props)) { | |
this.setInitialProps(); | |
} | |
}; | |
GraphQL.prototype.componentDidMount = function () { | |
this.hasMounted = true; | |
if (this.type === DocumentType.Mutation) | |
return; | |
if (!this.shouldSkip(this.props)) { | |
this.subscribeToQuery(); | |
if (this.refetcherQueue) { | |
var _a = this.refetcherQueue, args = _a.args, resolve = _a.resolve, reject = _a.reject; | |
this.queryObservable | |
.refetch(args) | |
.then(resolve) | |
.catch(reject); | |
} | |
} | |
}; | |
GraphQL.prototype.componentWillReceiveProps = function (nextProps, nextContext) { | |
if (this.shouldSkip(nextProps)) { | |
if (!this.shouldSkip(this.props)) { | |
this.unsubscribeFromQuery(); | |
} | |
return; | |
} | |
var client = mapPropsToOptions(nextProps).client; | |
if (shallowEqual(this.props, nextProps) && | |
(this.client === client || this.client === nextContext.client)) { | |
return; | |
} | |
this.shouldRerender = true; | |
if (this.client !== client && this.client !== nextContext.client) { | |
if (client) { | |
this.client = client; | |
} | |
else { | |
this.client = nextContext.client; | |
} | |
this.unsubscribeFromQuery(); | |
this.queryObservable = null; | |
this.previousData = {}; | |
this.updateQuery(nextProps); | |
if (!this.shouldSkip(nextProps)) { | |
this.subscribeToQuery(); | |
} | |
return; | |
} | |
if (this.type === DocumentType.Mutation) { | |
return; | |
} | |
if (this.type === DocumentType.Subscription && | |
operationOptions.shouldResubscribe && | |
operationOptions.shouldResubscribe(this.props, nextProps)) { | |
this.unsubscribeFromQuery(); | |
delete this.queryObservable; | |
this.updateQuery(nextProps); | |
this.subscribeToQuery(); | |
return; | |
} | |
this.updateQuery(nextProps); | |
this.subscribeToQuery(); | |
}; | |
GraphQL.prototype.componentWillUnmount = function () { | |
if (this.type === DocumentType.Query) { | |
if (this.queryObservable) { | |
var recycler = this.getQueryRecycler(); | |
if (recycler) { | |
recycler.recycle(this.queryObservable); | |
delete this.queryObservable; | |
} | |
} | |
this.unsubscribeFromQuery(); | |
} | |
if (this.type === DocumentType.Subscription) | |
this.unsubscribeFromQuery(); | |
this.hasMounted = false; | |
}; | |
GraphQL.prototype.getQueryRecycler = function () { | |
return (this.context.getQueryRecycler && | |
this.context.getQueryRecycler(GraphQL)); | |
}; | |
GraphQL.prototype.getClient = function (props) { | |
if (this.client) | |
return this.client; | |
var client = mapPropsToOptions(props).client; | |
if (client) { | |
this.client = client; | |
} | |
else { | |
this.client = this.context.client; | |
} | |
invariant(!!this.client, "Could not find \"client\" in the context of " + | |
("\"" + graphQLDisplayName + "\". ") + | |
"Wrap the root component in an <ApolloProvider>"); | |
return this.client; | |
}; | |
GraphQL.prototype.calculateOptions = function (props, newOpts) { | |
if (props === void 0) { props = this.props; } | |
var opts = mapPropsToOptions(props); | |
if (newOpts && newOpts.variables) { | |
newOpts.variables = assign({}, opts.variables, newOpts.variables); | |
} | |
if (newOpts) | |
opts = assign({}, opts, newOpts); | |
if (opts.variables || !operation.variables.length) | |
return opts; | |
var variables = {}; | |
for (var _i = 0, _a = operation.variables; _i < _a.length; _i++) { | |
var _b = _a[_i], variable = _b.variable, type = _b.type; | |
if (!variable.name || !variable.name.value) | |
continue; | |
if (typeof props[variable.name.value] !== 'undefined') { | |
variables[variable.name.value] = props[variable.name.value]; | |
continue; | |
} | |
if (type.kind !== 'NonNullType') { | |
variables[variable.name.value] = null; | |
continue; | |
} | |
invariant(typeof props[variable.name.value] !== 'undefined', "The operation '" + operation.name + "' wrapping '" + getDisplayName(WrappedComponent) + "' " + | |
("is expecting a variable: '" + variable.name | |
.value + "' but it was not found in the props ") + | |
("passed to '" + graphQLDisplayName + "'")); | |
} | |
opts = __assign({}, opts, { variables: variables }); | |
return opts; | |
}; | |
GraphQL.prototype.calculateResultProps = function (result) { | |
var name = this.type === DocumentType.Mutation ? 'mutate' : 'data'; | |
if (operationOptions.name) | |
name = operationOptions.name; | |
var newResult = (_a = {}, | |
_a[name] = result, | |
_a.ownProps = this.props, | |
_a); | |
if (mapResultToProps) | |
return mapResultToProps(newResult); | |
return _b = {}, _b[name] = defaultMapResultToProps(result), _b; | |
var _a, _b; | |
}; | |
GraphQL.prototype.setInitialProps = function () { | |
if (this.type === DocumentType.Mutation) { | |
return; | |
} | |
var opts = this.calculateOptions(this.props); | |
this.createQuery(opts); | |
}; | |
GraphQL.prototype.createQuery = function (opts, props) { | |
if (props === void 0) { props = this.props; } | |
if (this.type === DocumentType.Subscription) { | |
this.queryObservable = this.getClient(props).subscribe(assign({ query: document }, opts)); | |
} | |
else { | |
var recycler = this.getQueryRecycler(); | |
var queryObservable = null; | |
if (recycler) | |
queryObservable = recycler.reuse(opts); | |
if (queryObservable === null) { | |
this.queryObservable = this.getClient(props).watchQuery(assign({ | |
query: document, | |
metadata: { | |
reactComponent: { | |
displayName: graphQLDisplayName, | |
}, | |
}, | |
}, opts)); | |
} | |
else { | |
this.queryObservable = queryObservable; | |
} | |
} | |
}; | |
GraphQL.prototype.updateQuery = function (props) { | |
var opts = this.calculateOptions(props); | |
if (!this.queryObservable) { | |
this.createQuery(opts, props); | |
} | |
if (this.queryObservable._setOptionsNoResult) { | |
this.queryObservable._setOptionsNoResult(opts); | |
} | |
else { | |
if (this.queryObservable.setOptions) { | |
this.queryObservable | |
.setOptions(opts) | |
.catch(function () { return null; }); | |
} | |
} | |
}; | |
GraphQL.prototype.fetchData = function () { | |
if (this.shouldSkip()) | |
return false; | |
if (operation.type === DocumentType.Mutation || | |
operation.type === DocumentType.Subscription) | |
return false; | |
var opts = this.calculateOptions(); | |
if (opts.ssr === false) | |
return false; | |
if (opts.fetchPolicy === 'network-only' || | |
opts.fetchPolicy === 'cache-and-network') { | |
opts.fetchPolicy = 'cache-first'; | |
} | |
var observable = this.getClient(this.props).watchQuery(assign({ query: document }, opts)); | |
var result = observable.currentResult(); | |
if (result.loading) { | |
return observable.result(); | |
} | |
else { | |
return false; | |
} | |
}; | |
GraphQL.prototype.subscribeToQuery = function () { | |
var _this = this; | |
if (this.querySubscription) { | |
return; | |
} | |
var next = function (results) { | |
if (_this.type === DocumentType.Subscription) { | |
_this.lastSubscriptionData = results; | |
results = { data: results }; | |
} | |
var clashingKeys = Object.keys(observableQueryFields(results.data)); | |
invariant(clashingKeys.length === 0, "the result of the '" + graphQLDisplayName + "' operation contains keys that " + | |
"conflict with the return object." + | |
clashingKeys.map(function (k) { return "'" + k + "'"; }).join(', ') + | |
" not allowed."); | |
_this.forceRenderChildren(); | |
}; | |
var handleError = function (error) { | |
if (error.hasOwnProperty('graphQLErrors')) | |
return next({ error: error }); | |
throw error; | |
}; | |
this.querySubscription = this.queryObservable.subscribe({ | |
next: next, | |
error: handleError, | |
}); | |
}; | |
GraphQL.prototype.unsubscribeFromQuery = function () { | |
if (this.querySubscription) { | |
this.querySubscription.unsubscribe(); | |
delete this.querySubscription; | |
} | |
}; | |
GraphQL.prototype.shouldSkip = function (props) { | |
if (props === void 0) { props = this.props; } | |
return (mapPropsToSkip(props) || mapPropsToOptions(props).skip); | |
}; | |
GraphQL.prototype.forceRenderChildren = function () { | |
this.shouldRerender = true; | |
if (this.hasMounted) | |
this.forceUpdate(); | |
}; | |
GraphQL.prototype.getWrappedInstance = function () { | |
invariant(operationOptions.withRef, "To access the wrapped instance, you need to specify " + | |
"{ withRef: true } in the options"); | |
return this.wrappedInstance; | |
}; | |
GraphQL.prototype.setWrappedInstance = function (ref) { | |
this.wrappedInstance = ref; | |
}; | |
GraphQL.prototype.dataForChildViaMutation = function (mutationOpts) { | |
var opts = this.calculateOptions(this.props, mutationOpts); | |
if (typeof opts.variables === 'undefined') | |
delete opts.variables; | |
opts.mutation = document; | |
return this.getClient(this.props).mutate(opts); | |
}; | |
GraphQL.prototype.dataForChild = function () { | |
var _this = this; | |
if (this.type === DocumentType.Mutation) { | |
return this.dataForChildViaMutation; | |
} | |
var opts = this.calculateOptions(this.props); | |
var data = {}; | |
assign(data, observableQueryFields(this.queryObservable)); | |
if (this.type === DocumentType.Subscription) { | |
assign(data, { | |
loading: !this.lastSubscriptionData, | |
variables: opts.variables, | |
}, this.lastSubscriptionData); | |
} | |
else { | |
var currentResult = this.queryObservable.currentResult(); | |
var loading = currentResult.loading, error_1 = currentResult.error, networkStatus = currentResult.networkStatus; | |
assign(data, { loading: loading, networkStatus: networkStatus }); | |
var logErrorTimeoutId_1 = setTimeout(function () { | |
if (error_1) { | |
console.error('Unhandled (in react-apollo)', error_1.stack || error_1); | |
} | |
}, 10); | |
Object.defineProperty(data, 'error', { | |
configurable: true, | |
enumerable: true, | |
get: function () { | |
clearTimeout(logErrorTimeoutId_1); | |
return error_1; | |
}, | |
}); | |
if (loading) { | |
assign(data, this.previousData, currentResult.data); | |
} | |
else if (error_1) { | |
assign(data, (this.queryObservable.getLastResult() || {}).data, { | |
retry: () => { | |
this.unsubscribeFromQuery(); | |
this.queryObservable = null; | |
this.previousData = {}; | |
this.updateQuery(this.props); | |
if (!this.shouldSkip(this.props)) { | |
this.subscribeToQuery(); | |
} | |
} | |
}); | |
} | |
else { | |
assign(data, currentResult.data); | |
this.previousData = currentResult.data; | |
} | |
if (!this.querySubscription) { | |
data.refetch = function (args) { | |
return new Promise(function (r, f) { | |
_this.refetcherQueue = { resolve: r, reject: f, args: args }; | |
}); | |
}; | |
} | |
} | |
return data; | |
}; | |
GraphQL.prototype.render = function () { | |
if (this.shouldSkip()) { | |
if (operationOptions.withRef) { | |
return createElement(WrappedComponent, assign({}, this.props, { ref: this.setWrappedInstance })); | |
} | |
return createElement(WrappedComponent, this.props); | |
} | |
var _a = this, shouldRerender = _a.shouldRerender, renderedElement = _a.renderedElement, props = _a.props; | |
this.shouldRerender = false; | |
if (!shouldRerender && | |
renderedElement && | |
renderedElement.type === WrappedComponent) { | |
return renderedElement; | |
} | |
var data = this.dataForChild(); | |
var clientProps = this.calculateResultProps(data); | |
var mergedPropsAndData = assign({}, props, clientProps); | |
if (operationOptions.withRef) | |
mergedPropsAndData.ref = this.setWrappedInstance; | |
this.renderedElement = createElement(WrappedComponent, mergedPropsAndData); | |
return this.renderedElement; | |
}; | |
GraphQL.displayName = graphQLDisplayName; | |
GraphQL.WrappedComponent = WrappedComponent; | |
GraphQL.contextTypes = { | |
client: PropTypes.object, | |
getQueryRecycler: PropTypes.func, | |
}; | |
return GraphQL; | |
}(Component)); | |
return hoistNonReactStatics(GraphQL, WrappedComponent, {}); | |
} | |
return wrapWithApolloComponent; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var invariant = require('invariant'); | |
export var DocumentType; | |
(function (DocumentType) { | |
DocumentType[DocumentType["Query"] = 0] = "Query"; | |
DocumentType[DocumentType["Mutation"] = 1] = "Mutation"; | |
DocumentType[DocumentType["Subscription"] = 2] = "Subscription"; | |
})(DocumentType || (DocumentType = {})); | |
export function parser(document) { | |
var variables, type, name; | |
invariant(!!document && !!document.kind, "Argument of " + document + " passed to parser was not a valid GraphQL DocumentNode. You may need to use 'graphql-tag' or another method to convert your operation into a document"); | |
var fragments = document.definitions.filter(function (x) { return x.kind === 'FragmentDefinition'; }); | |
var queries = document.definitions.filter(function (x) { | |
return x.kind === 'OperationDefinition' && x.operation === 'query'; | |
}); | |
var mutations = document.definitions.filter(function (x) { | |
return x.kind === 'OperationDefinition' && x.operation === 'mutation'; | |
}); | |
var subscriptions = document.definitions.filter(function (x) { | |
return x.kind === 'OperationDefinition' && x.operation === 'subscription'; | |
}); | |
invariant(!fragments.length || | |
(queries.length || mutations.length || subscriptions.length), "Passing only a fragment to 'graphql' is not yet supported. You must include a query, subscription or mutation as well"); | |
invariant(queries.length + mutations.length + subscriptions.length <= 1, "react-apollo only supports a query, subscription, or a mutation per HOC. " + document + " had " + queries.length + " queries, " + subscriptions.length + " subscriptions and " + mutations.length + " mutations. You can use 'compose' to join multiple operation types to a component"); | |
type = queries.length ? DocumentType.Query : DocumentType.Mutation; | |
if (!queries.length && !mutations.length) | |
type = DocumentType.Subscription; | |
var definitions = queries.length | |
? queries | |
: mutations.length ? mutations : subscriptions; | |
invariant(definitions.length === 1, "react-apollo only supports one defintion per HOC. " + document + " had " + definitions.length + " definitions. You can use 'compose' to join multiple operation types to a component"); | |
var definition = definitions[0]; | |
variables = definition.variableDefinitions || []; | |
var hasName = definition.name && definition.name.kind === 'Name'; | |
name = hasName ? definition.name.value : 'data'; | |
return { name: name, type: type, variables: variables }; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default function shallowEqual(objA, objB) { | |
if (!objA || !objB) | |
return false; | |
if (objA === objB) | |
return true; | |
var keysA = Object.keys(objA); | |
var keysB = Object.keys(objB); | |
if (keysA.length !== keysB.length) | |
return false; | |
var hasOwn = Object.prototype.hasOwnProperty; | |
for (var i = 0; i < keysA.length; i++) { | |
if (!hasOwn.call(objB, keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) { | |
return false; | |
} | |
} | |
return true; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment