@urql/exchange-populate
Advanced tools
Comparing version 1.0.0 to 1.1.0
# @urql/exchange-populate | ||
## 1.1.0 | ||
### Minor Changes | ||
- Introduce `maxDepth` and `skipType` into the `populateExchange`, these options allow you to specify | ||
the maximum depth a mutation should be populated as well as which types should not be counted towards | ||
this depth | ||
Submitted by [@JoviDeCroock](https://github.com/JoviDeCroock) (See [#3023](https://github.com/urql-graphql/urql/pull/3023)) | ||
### Patch Changes | ||
- Updated dependencies (See [#3007](https://github.com/urql-graphql/urql/pull/3007), [#2962](https://github.com/urql-graphql/urql/pull/2962), [#3007](https://github.com/urql-graphql/urql/pull/3007), [#3015](https://github.com/urql-graphql/urql/pull/3015), and [#3022](https://github.com/urql-graphql/urql/pull/3022)) | ||
- @urql/core@3.2.0 | ||
## 1.0.0 | ||
@@ -4,0 +18,0 @@ |
Object.defineProperty(exports, '__esModule', { | ||
value: true | ||
}); | ||
var graphql = require('graphql'); | ||
var wonka = require('wonka'); | ||
var core = require('@urql/core'); | ||
var core = require('@urql/core'); // URL unfurls to https://formidable.com/open-source/urql/docs/graphcache/errors/ | ||
const helpUrl = '\nhttps://bit.ly/2XbVrpR#'; | ||
const cache = new Set(); | ||
function warn(message, code) { | ||
if (!cache.has(message)) { | ||
console.warn(message + helpUrl + code); | ||
cache.add(message); | ||
} | ||
} | ||
/** Returns the name of a given node */ | ||
const getName = node => node.name.value; | ||
/** Returns the SelectionSet for a given inline or defined fragment node */ | ||
const getSelectionSet = node => node.selectionSet !== undefined ? node.selectionSet.selections : []; | ||
const unwrapType = type => { | ||
var getName = node => node.name.value; | ||
var unwrapType = type => { | ||
if (graphql.isWrappingType(type)) { | ||
return unwrapType(type.ofType); | ||
} | ||
return type || null; | ||
}; | ||
function createNameNode(value) { | ||
return { | ||
kind: graphql.Kind.NAME, | ||
value | ||
}; | ||
} | ||
function traverse(node, enter, exit) { | ||
@@ -49,7 +20,7 @@ if (enter) { | ||
} | ||
switch (node.kind) { | ||
case graphql.Kind.DOCUMENT: | ||
{ | ||
node = { ...node, | ||
node = { | ||
...node, | ||
definitions: node.definitions.map(n => traverse(n, enter, exit)) | ||
@@ -59,3 +30,2 @@ }; | ||
} | ||
case graphql.Kind.OPERATION_DEFINITION: | ||
@@ -66,4 +36,6 @@ case graphql.Kind.FIELD: | ||
if (node.selectionSet) { | ||
node = { ...node, | ||
selectionSet: { ...node.selectionSet, | ||
node = { | ||
...node, | ||
selectionSet: { | ||
...node.selectionSet, | ||
selections: node.selectionSet.selections.map(n => traverse(n, enter, exit)) | ||
@@ -73,95 +45,276 @@ } | ||
} | ||
break; | ||
} | ||
} | ||
if (exit) { | ||
node = exit(node) || node; | ||
} | ||
return node; | ||
} | ||
function resolveFields(schema, visits) { | ||
let currentFields = schema.getQueryType().getFields(); | ||
for (let i = 0; i < visits.length; i++) { | ||
const t = unwrapType(currentFields[visits[i]].type); | ||
if (graphql.isAbstractType(t)) { | ||
currentFields = {}; | ||
schema.getPossibleTypes(t).forEach(implementedType => { | ||
currentFields = { ...currentFields, | ||
// @ts-ignore TODO: proper casting | ||
...schema.getType(implementedType.name).toConfig().fields | ||
}; | ||
}); | ||
} else { | ||
// @ts-ignore TODO: proper casting | ||
currentFields = schema.getType(t.name).toConfig().fields; | ||
} | ||
} | ||
return currentFields; | ||
} | ||
/** Get fragment names referenced by node. */ | ||
function getUsedFragmentNames(node) { | ||
const names = []; | ||
traverse(node, n => { | ||
if (n.kind === graphql.Kind.FRAGMENT_SPREAD) { | ||
names.push(getName(n)); | ||
} | ||
}); | ||
return names; | ||
} | ||
const makeDict = () => Object.create(null); | ||
/** An exchange for auto-populating mutations with a required response body. */ | ||
const populateExchange = ({ | ||
schema: ogSchema | ||
var makeDict = () => Object.create(null); | ||
var SKIP_COUNT_TYPE = /^PageInfo|(Connection|Edge)$/; | ||
/** Creates an `Exchange` handing automatic mutation selection-set population based on the | ||
* query selection-sets seen. | ||
* | ||
* | ||
* @remarks | ||
* The `populateExchange` will create an exchange that monitors queries and | ||
* extracts fields and types so it knows what is currently observed by your | ||
* application. | ||
* When a mutation comes in with the `@populate` directive it will fill the | ||
* selection-set based on these prior queries. | ||
* | ||
* This Exchange can ease up the transition from documentCache to graphCache | ||
* | ||
* @example | ||
* ```ts | ||
* populateExchange({ schema, options: { maxDepth: 3, skipType: /Todo/ }}) | ||
* | ||
* const query = gql` | ||
* mutation { addTodo @popualte } | ||
* ` | ||
* ``` | ||
*/ | ||
var populateExchange = ({ | ||
schema: ogSchema, | ||
options | ||
}) => ({ | ||
forward | ||
}) => { | ||
const schema = graphql.buildClientSchema(ogSchema); | ||
var maxDepth = options && options.maxDepth || 2; | ||
var skipType = options && options.skipType || SKIP_COUNT_TYPE; | ||
var schema = graphql.buildClientSchema(ogSchema); | ||
/** List of operation keys that have already been parsed. */ | ||
const parsedOperations = new Set(); | ||
var parsedOperations = new Set(); | ||
/** List of operation keys that have not been torn down. */ | ||
const activeOperations = new Set(); | ||
var activeOperations = new Set(); | ||
/** Collection of fragments used by the user. */ | ||
const userFragments = makeDict(); | ||
/** Collection of actively in use type fragments. */ | ||
const activeTypeFragments = makeDict(); | ||
var userFragments = makeDict(); | ||
// State of the global types & their fields | ||
var typeFields = new Map(); | ||
var currentVariables = {}; | ||
/** Handle mutation and inject selections + fragments. */ | ||
const handleIncomingMutation = op => { | ||
var handleIncomingMutation = op => { | ||
if (op.kind !== 'mutation') { | ||
return op; | ||
} | ||
const activeSelections = makeDict(); | ||
for (const name in activeTypeFragments) { | ||
activeSelections[name] = activeTypeFragments[name].filter(s => activeOperations.has(s.key)); | ||
var document = traverse(op.query, node => { | ||
if (node.kind === graphql.Kind.FIELD) { | ||
if (!node.directives) return; | ||
var directives = node.directives.filter(d => getName(d) !== 'populate'); | ||
if (directives.length === node.directives.length) return; | ||
var field = schema.getMutationType().getFields()[node.name.value]; | ||
if (!field) return; | ||
var type = unwrapType(field.type); | ||
if (!type) { | ||
return { | ||
...node, | ||
selectionSet: { | ||
kind: graphql.Kind.SELECTION_SET, | ||
selections: [{ | ||
kind: graphql.Kind.FIELD, | ||
name: { | ||
kind: graphql.Kind.NAME, | ||
value: '__typename' | ||
} | ||
}] | ||
}, | ||
directives | ||
}; | ||
} | ||
var visited = new Set(); | ||
var populateSelections = (type, selections, depth) => { | ||
var possibleTypes = []; | ||
var isAbstract = false; | ||
if (graphql.isAbstractType(type)) { | ||
isAbstract = true; | ||
possibleTypes = schema.getPossibleTypes(type).map(x => x.name); | ||
} else { | ||
possibleTypes = [type.name]; | ||
} | ||
possibleTypes.forEach(typeName => { | ||
var fieldsForType = typeFields.get(typeName); | ||
if (!fieldsForType) { | ||
if (possibleTypes.length === 1) { | ||
selections.push({ | ||
kind: graphql.Kind.FIELD, | ||
name: { | ||
kind: graphql.Kind.NAME, | ||
value: '__typename' | ||
} | ||
}); | ||
} | ||
return; | ||
} | ||
var typeSelections = selections; | ||
if (isAbstract) { | ||
typeSelections = [{ | ||
kind: graphql.Kind.FIELD, | ||
name: { | ||
kind: graphql.Kind.NAME, | ||
value: '__typename' | ||
} | ||
}]; | ||
selections.push({ | ||
kind: graphql.Kind.INLINE_FRAGMENT, | ||
typeCondition: { | ||
kind: graphql.Kind.NAMED_TYPE, | ||
name: { | ||
kind: graphql.Kind.NAME, | ||
value: typeName | ||
} | ||
}, | ||
selectionSet: { | ||
kind: graphql.Kind.SELECTION_SET, | ||
selections: typeSelections | ||
} | ||
}); | ||
} else { | ||
typeSelections.push({ | ||
kind: graphql.Kind.FIELD, | ||
name: { | ||
kind: graphql.Kind.NAME, | ||
value: '__typename' | ||
} | ||
}); | ||
} | ||
Object.keys(fieldsForType).forEach(key => { | ||
var value = fieldsForType[key]; | ||
if (value.type instanceof graphql.GraphQLScalarType) { | ||
var args = value.args ? Object.keys(value.args).map(k => { | ||
var v = value.args[k]; | ||
return { | ||
kind: graphql.Kind.ARGUMENT, | ||
value: { | ||
kind: v.kind, | ||
value: v.value | ||
}, | ||
name: { | ||
kind: graphql.Kind.NAME, | ||
value: k | ||
} | ||
}; | ||
}) : []; | ||
var _field = { | ||
kind: graphql.Kind.FIELD, | ||
arguments: args, | ||
name: { | ||
kind: graphql.Kind.NAME, | ||
value: value.fieldName | ||
} | ||
}; | ||
typeSelections.push(_field); | ||
} else if (value.type instanceof graphql.GraphQLObjectType && !visited.has(value.type.name) && depth < maxDepth) { | ||
visited.add(value.type.name); | ||
var fieldSelections = []; | ||
populateSelections(value.type, fieldSelections, skipType.test(value.type.name) ? depth : depth + 1); | ||
var _args = value.args ? Object.keys(value.args).map(k => { | ||
var v = value.args[k]; | ||
return { | ||
kind: graphql.Kind.ARGUMENT, | ||
value: { | ||
kind: v.kind, | ||
value: v.value | ||
}, | ||
name: { | ||
kind: graphql.Kind.NAME, | ||
value: k | ||
} | ||
}; | ||
}) : []; | ||
var _field2 = { | ||
kind: graphql.Kind.FIELD, | ||
selectionSet: { | ||
kind: graphql.Kind.SELECTION_SET, | ||
selections: fieldSelections | ||
}, | ||
arguments: _args, | ||
name: { | ||
kind: graphql.Kind.NAME, | ||
value: value.fieldName | ||
} | ||
}; | ||
typeSelections.push(_field2); | ||
} | ||
}); | ||
}); | ||
}; | ||
visited.add(type.name); | ||
var selections = node.selectionSet ? [...node.selectionSet.selections] : []; | ||
populateSelections(type, selections, 0); | ||
return { | ||
...node, | ||
selectionSet: { | ||
kind: graphql.Kind.SELECTION_SET, | ||
selections | ||
}, | ||
directives | ||
}; | ||
} | ||
}); | ||
return { | ||
...op, | ||
query: document | ||
}; | ||
}; | ||
var readFromSelectionSet = (type, selections, seenFields = {}) => { | ||
if (graphql.isAbstractType(type)) { | ||
// TODO: should we add this to typeParents/typeFields as well? | ||
schema.getPossibleTypes(type).forEach(t => { | ||
readFromSelectionSet(t, selections); | ||
}); | ||
} else { | ||
var fieldMap = type.getFields(); | ||
var args = null; | ||
for (var i = 0; i < selections.length; i++) { | ||
var selection = selections[i]; | ||
if (selection.kind === graphql.Kind.FRAGMENT_SPREAD) { | ||
var fragmentName = getName(selection); | ||
var fragment = userFragments[fragmentName]; | ||
if (fragment) { | ||
readFromSelectionSet(type, fragment.selectionSet.selections); | ||
} | ||
continue; | ||
} | ||
if (selection.kind === graphql.Kind.INLINE_FRAGMENT) { | ||
readFromSelectionSet(type, selection.selectionSet.selections); | ||
continue; | ||
} | ||
if (selection.kind !== graphql.Kind.FIELD) continue; | ||
var fieldName = selection.name.value; | ||
if (!fieldMap[fieldName]) continue; | ||
var ownerType = seenFields[fieldName] || (seenFields[fieldName] = type); | ||
var fields = typeFields.get(ownerType.name); | ||
if (!fields) typeFields.set(type.name, fields = {}); | ||
var childType = unwrapType(fieldMap[fieldName].type); | ||
if (selection.arguments && selection.arguments.length) { | ||
args = {}; | ||
for (var j = 0; j < selection.arguments.length; j++) { | ||
var argNode = selection.arguments[j]; | ||
args[argNode.name.value] = { | ||
value: graphql.valueFromASTUntyped(argNode.value, currentVariables), | ||
kind: argNode.value.kind | ||
}; | ||
} | ||
} | ||
var fieldKey = args ? `${fieldName}:${core.stringifyVariables(args)}` : fieldName; | ||
if (!fields[fieldKey]) { | ||
fields[fieldKey] = { | ||
type: childType, | ||
args, | ||
fieldName | ||
}; | ||
} | ||
if (selection.selectionSet) { | ||
readFromSelectionSet(childType, selection.selectionSet.selections); | ||
} | ||
} | ||
} | ||
const newOperation = core.makeOperation(op.kind, op); | ||
newOperation.query = addFragmentsToQuery(schema, op.query, activeSelections, userFragments); | ||
return newOperation; | ||
}; | ||
/** Handle query and extract fragments. */ | ||
const handleIncomingQuery = ({ | ||
var handleIncomingQuery = ({ | ||
key, | ||
kind, | ||
query | ||
query, | ||
variables | ||
}) => { | ||
@@ -171,33 +324,24 @@ if (kind !== 'query') { | ||
} | ||
activeOperations.add(key); | ||
if (parsedOperations.has(key)) { | ||
return; | ||
} | ||
parsedOperations.add(key); | ||
const [extractedFragments, newFragments] = extractSelectionsFromQuery(schema, query); | ||
for (let i = 0, l = extractedFragments.length; i < l; i++) { | ||
const fragment = extractedFragments[i]; | ||
userFragments[getName(fragment)] = fragment; | ||
currentVariables = variables || {}; | ||
for (var i = query.definitions.length; i--;) { | ||
var definition = query.definitions[i]; | ||
if (definition.kind === graphql.Kind.FRAGMENT_DEFINITION) { | ||
userFragments[getName(definition)] = definition; | ||
} else if (definition.kind === graphql.Kind.OPERATION_DEFINITION) { | ||
var type = schema.getQueryType(); | ||
readFromSelectionSet(unwrapType(type), definition.selectionSet.selections); | ||
} | ||
} | ||
for (let i = 0, l = newFragments.length; i < l; i++) { | ||
const fragment = newFragments[i]; | ||
const type = getName(fragment.typeCondition); | ||
const current = activeTypeFragments[type] || (activeTypeFragments[type] = []); | ||
fragment.name.value += current.length; | ||
current.push({ | ||
key, | ||
fragment | ||
}); | ||
} | ||
}; | ||
const handleIncomingTeardown = ({ | ||
var handleIncomingTeardown = ({ | ||
key, | ||
kind | ||
}) => { | ||
// TODO: we might want to remove fields here, the risk becomes | ||
// that data in the cache would become stale potentially | ||
if (kind === 'teardown') { | ||
@@ -207,3 +351,2 @@ activeOperations.delete(key); | ||
}; | ||
return ops$ => { | ||
@@ -213,160 +356,3 @@ return forward(wonka.map(handleIncomingMutation)(wonka.tap(handleIncomingTeardown)(wonka.tap(handleIncomingQuery)(ops$)))); | ||
}; | ||
/** Gets typed selection sets and fragments from query */ | ||
const extractSelectionsFromQuery = (schema, query) => { | ||
const extractedFragments = []; | ||
const newFragments = []; | ||
const sanitizeSelectionSet = (selectionSet, type) => { | ||
const selections = []; | ||
const validTypes = schema.getType(type).getFields(); | ||
selectionSet.selections.forEach(selection => { | ||
if (selection.kind === graphql.Kind.FIELD) { | ||
if (validTypes[selection.name.value]) { | ||
if (selection.selectionSet) { | ||
selections.push({ ...selection, | ||
selectionSet: sanitizeSelectionSet(selection.selectionSet, unwrapType(validTypes[selection.name.value].type).toString()) | ||
}); | ||
} else { | ||
selections.push(selection); | ||
} | ||
} | ||
} else { | ||
selections.push(selection); | ||
} | ||
}); | ||
return { ...selectionSet, | ||
selections | ||
}; | ||
}; | ||
const visits = []; | ||
traverse(query, node => { | ||
if (node.kind === graphql.Kind.FRAGMENT_DEFINITION) { | ||
extractedFragments.push(node); | ||
} else if (node.kind === graphql.Kind.FIELD && node.selectionSet) { | ||
const type = unwrapType(resolveFields(schema, visits)[node.name.value].type); | ||
visits.push(node.name.value); | ||
if (graphql.isAbstractType(type)) { | ||
const types = schema.getPossibleTypes(type); | ||
types.forEach(t => { | ||
newFragments.push({ | ||
kind: graphql.Kind.FRAGMENT_DEFINITION, | ||
typeCondition: { | ||
kind: graphql.Kind.NAMED_TYPE, | ||
name: createNameNode(t.toString()) | ||
}, | ||
name: createNameNode(`${t.toString()}_PopulateFragment_`), | ||
selectionSet: sanitizeSelectionSet(node.selectionSet, t.toString()) | ||
}); | ||
}); | ||
} else if (type) { | ||
newFragments.push({ | ||
kind: graphql.Kind.FRAGMENT_DEFINITION, | ||
typeCondition: { | ||
kind: graphql.Kind.NAMED_TYPE, | ||
name: createNameNode(type.toString()) | ||
}, | ||
name: createNameNode(`${type.toString()}_PopulateFragment_`), | ||
selectionSet: node.selectionSet | ||
}); | ||
} | ||
} | ||
}, node => { | ||
if (node.kind === graphql.Kind.FIELD && node.selectionSet) visits.pop(); | ||
}); | ||
return [extractedFragments, newFragments]; | ||
}; | ||
/** Replaces populate decorator with fragment spreads + fragments. */ | ||
const addFragmentsToQuery = (schema, query, activeTypeFragments, userFragments) => { | ||
const requiredUserFragments = makeDict(); | ||
const additionalFragments = makeDict(); | ||
/** Fragments provided and used by the current query */ | ||
const existingFragmentsForQuery = new Set(); | ||
return traverse(query, node => { | ||
if (node.kind === graphql.Kind.DOCUMENT) { | ||
node.definitions.reduce((set, definition) => { | ||
if (definition.kind === graphql.Kind.FRAGMENT_DEFINITION) { | ||
set.add(definition.name.value); | ||
} | ||
return set; | ||
}, existingFragmentsForQuery); | ||
} else if (node.kind === graphql.Kind.FIELD) { | ||
if (!node.directives) return; | ||
const directives = node.directives.filter(d => getName(d) !== 'populate'); | ||
if (directives.length === node.directives.length) return; | ||
const type = unwrapType(schema.getMutationType().getFields()[node.name.value].type); | ||
let possibleTypes = []; | ||
if (process.env.NODE_ENV !== 'production') { | ||
if (!graphql.isCompositeType(type)) { | ||
warn('Invalid type: The type `' + type + '` is used with @populate but does not exist.', 17); | ||
} else { | ||
possibleTypes = graphql.isAbstractType(type) ? schema.getPossibleTypes(type) : [type]; | ||
} | ||
} | ||
const newSelections = possibleTypes.reduce((p, possibleType) => { | ||
const typeFrags = activeTypeFragments[possibleType.name]; | ||
if (!typeFrags) { | ||
return p; | ||
} | ||
for (let i = 0, l = typeFrags.length; i < l; i++) { | ||
const { | ||
fragment | ||
} = typeFrags[i]; | ||
const fragmentName = getName(fragment); | ||
const usedFragments = getUsedFragmentNames(fragment); // Add used fragment for insertion at Document node | ||
for (let j = 0, l = usedFragments.length; j < l; j++) { | ||
const name = usedFragments[j]; | ||
if (!existingFragmentsForQuery.has(name)) { | ||
requiredUserFragments[name] = userFragments[name]; | ||
} | ||
} // Add fragment for insertion at Document node | ||
additionalFragments[fragmentName] = fragment; | ||
p.push({ | ||
kind: graphql.Kind.FRAGMENT_SPREAD, | ||
name: createNameNode(fragmentName) | ||
}); | ||
} | ||
return p; | ||
}, []); | ||
const existingSelections = getSelectionSet(node); | ||
const selections = existingSelections.length || newSelections.length ? [...newSelections, ...existingSelections] : [{ | ||
kind: graphql.Kind.FIELD, | ||
name: createNameNode('__typename') | ||
}]; | ||
return { ...node, | ||
directives, | ||
selectionSet: { | ||
kind: graphql.Kind.SELECTION_SET, | ||
selections | ||
} | ||
}; | ||
} | ||
}, node => { | ||
if (node.kind === graphql.Kind.DOCUMENT) { | ||
return { ...node, | ||
definitions: [...node.definitions, ...Object.keys(additionalFragments).map(key => additionalFragments[key]), ...Object.keys(requiredUserFragments).map(key => requiredUserFragments[key])] | ||
}; | ||
} | ||
}); | ||
}; | ||
exports.addFragmentsToQuery = addFragmentsToQuery; | ||
exports.extractSelectionsFromQuery = extractSelectionsFromQuery; | ||
exports.populateExchange = populateExchange; | ||
//# sourceMappingURL=urql-exchange-populate.js.map |
@@ -1,2 +0,2 @@ | ||
Object.defineProperty(exports,"__esModule",{value:!0});var e=require("graphql"),n=require("wonka"),t=require("@urql/core");new Set;const i=e=>e.name.value,s=n=>e.isWrappingType(n)?s(n.ofType):n||null;function o(n){return{kind:e.Kind.NAME,value:n}}function r(n,t,i){switch(t&&(n=t(n)||n),n.kind){case e.Kind.DOCUMENT:n={...n,definitions:n.definitions.map((e=>r(e,t,i)))};break;case e.Kind.OPERATION_DEFINITION:case e.Kind.FIELD:case e.Kind.FRAGMENT_DEFINITION:n.selectionSet&&(n={...n,selectionSet:{...n.selectionSet,selections:n.selectionSet.selections.map((e=>r(e,t,i)))}})}return i&&(n=i(n)||n),n}function d(n){const t=[];return r(n,(n=>{n.kind===e.Kind.FRAGMENT_SPREAD&&t.push(i(n))})),t}const a=()=>Object.create(null),l=(n,t)=>{const i=[],d=[],a=(t,i)=>{const o=[],r=n.getType(i).getFields();return t.selections.forEach((n=>{n.kind===e.Kind.FIELD?r[n.name.value]&&o.push(n.selectionSet?{...n,selectionSet:a(n.selectionSet,s(r[n.name.value].type).toString())}:n):o.push(n)})),{...t,selections:o}},l=[];return r(t,(t=>{if(t.kind===e.Kind.FRAGMENT_DEFINITION)i.push(t);else if(t.kind===e.Kind.FIELD&&t.selectionSet){const i=s(function(n,t){let i=n.getQueryType().getFields();for(let o=0;o<t.length;o++){const r=s(i[t[o]].type);e.isAbstractType(r)?(i={},n.getPossibleTypes(r).forEach((e=>{i={...i,...n.getType(e.name).toConfig().fields}}))):i=n.getType(r.name).toConfig().fields}return i}(n,l)[t.name.value].type);l.push(t.name.value),e.isAbstractType(i)?n.getPossibleTypes(i).forEach((n=>{d.push({kind:e.Kind.FRAGMENT_DEFINITION,typeCondition:{kind:e.Kind.NAMED_TYPE,name:o(n.toString())},name:o(`${n.toString()}_PopulateFragment_`),selectionSet:a(t.selectionSet,n.toString())})})):i&&d.push({kind:e.Kind.FRAGMENT_DEFINITION,typeCondition:{kind:e.Kind.NAMED_TYPE,name:o(i.toString())},name:o(`${i.toString()}_PopulateFragment_`),selectionSet:t.selectionSet})}}),(n=>{n.kind===e.Kind.FIELD&&n.selectionSet&&l.pop()})),[i,d]},c=(n,t,l,c)=>{const u=a(),p=a(),f=new Set;return r(t,(t=>{if(t.kind===e.Kind.DOCUMENT)t.definitions.reduce(((n,t)=>(t.kind===e.Kind.FRAGMENT_DEFINITION&&n.add(t.name.value),n)),f);else if(t.kind===e.Kind.FIELD){if(!t.directives)return;const r=t.directives.filter((e=>"populate"!==i(e)));if(r.length===t.directives.length)return;s(n.getMutationType().getFields()[t.name.value].type);const a=[].reduce(((n,t)=>{const s=l[t.name];if(!s)return n;for(let t=0,r=s.length;t<r;t++){const{fragment:r}=s[t],a=i(r),l=d(r);for(let e=0,n=l.length;e<n;e++){const n=l[e];f.has(n)||(u[n]=c[n])}p[a]=r,n.push({kind:e.Kind.FRAGMENT_SPREAD,name:o(a)})}return n}),[]),E=(e=>void 0!==e.selectionSet?e.selectionSet.selections:[])(t),g=E.length||a.length?[...a,...E]:[{kind:e.Kind.FIELD,name:o("__typename")}];return{...t,directives:r,selectionSet:{kind:e.Kind.SELECTION_SET,selections:g}}}}),(n=>{if(n.kind===e.Kind.DOCUMENT)return{...n,definitions:[...n.definitions,...Object.keys(p).map((e=>p[e])),...Object.keys(u).map((e=>u[e]))]}}))};exports.addFragmentsToQuery=c,exports.extractSelectionsFromQuery=l,exports.populateExchange=({schema:s})=>({forward:o})=>{const r=e.buildClientSchema(s),d=new Set,u=new Set,p=a(),f=a(),E=e=>{if("mutation"!==e.kind)return e;const n=a();for(const e in f)n[e]=f[e].filter((e=>u.has(e.key)));const i=t.makeOperation(e.kind,e);return i.query=c(r,e.query,n,p),i},g=({key:e,kind:n,query:t})=>{if("query"!==n)return;if(u.add(e),d.has(e))return;d.add(e);const[s,o]=l(r,t);for(let e=0,n=s.length;e<n;e++){const n=s[e];p[i(n)]=n}for(let n=0,t=o.length;n<t;n++){const t=o[n],s=i(t.typeCondition),r=f[s]||(f[s]=[]);t.name.value+=r.length,r.push({key:e,fragment:t})}},m=({key:e,kind:n})=>{"teardown"===n&&u.delete(e)};return e=>o(n.map(E)(n.tap(m)(n.tap(g)(e))))}; | ||
Object.defineProperty(exports,"__esModule",{value:!0});var e=require("graphql"),n=require("wonka"),i=require("@urql/core"),a=e=>e.name.value,t=n=>e.isWrappingType(n)?t(n.ofType):n||null;function r(n,i,a){switch(i&&(n=i(n)||n),n.kind){case e.Kind.DOCUMENT:n={...n,definitions:n.definitions.map((e=>r(e,i,a)))};break;case e.Kind.OPERATION_DEFINITION:case e.Kind.FIELD:case e.Kind.FRAGMENT_DEFINITION:n.selectionSet&&(n={...n,selectionSet:{...n.selectionSet,selections:n.selectionSet.selections.map((e=>r(e,i,a)))}})}return a&&(n=a(n)||n),n}var s=/^PageInfo|(Connection|Edge)$/;exports.populateExchange=({schema:d,options:l})=>({forward:u})=>{var o=l&&l.maxDepth||2,v=l&&l.skipType||s,c=e.buildClientSchema(d),p=new Set,E=new Set,k=Object.create(null),m=new Map,f={},N=n=>{if("mutation"!==n.kind)return n;var i=r(n.query,(n=>{if(n.kind===e.Kind.FIELD){if(!n.directives)return;var i=n.directives.filter((e=>"populate"!==a(e)));if(i.length===n.directives.length)return;var r=c.getMutationType().getFields()[n.name.value];if(!r)return;var s=t(r.type);if(!s)return{...n,selectionSet:{kind:e.Kind.SELECTION_SET,selections:[{kind:e.Kind.FIELD,name:{kind:e.Kind.NAME,value:"__typename"}}]},directives:i};var d=new Set,l=(n,i,a)=>{var t=[],r=!1;e.isAbstractType(n)?(r=!0,t=c.getPossibleTypes(n).map((e=>e.name))):t=[n.name],t.forEach((n=>{var s=m.get(n);if(s){var u=i;r?i.push({kind:e.Kind.INLINE_FRAGMENT,typeCondition:{kind:e.Kind.NAMED_TYPE,name:{kind:e.Kind.NAME,value:n}},selectionSet:{kind:e.Kind.SELECTION_SET,selections:u=[{kind:e.Kind.FIELD,name:{kind:e.Kind.NAME,value:"__typename"}}]}}):u.push({kind:e.Kind.FIELD,name:{kind:e.Kind.NAME,value:"__typename"}}),Object.keys(s).forEach((n=>{var i=s[n];if(i.type instanceof e.GraphQLScalarType){var t=i.args?Object.keys(i.args).map((n=>{var a=i.args[n];return{kind:e.Kind.ARGUMENT,value:{kind:a.kind,value:a.value},name:{kind:e.Kind.NAME,value:n}}})):[];u.push({kind:e.Kind.FIELD,arguments:t,name:{kind:e.Kind.NAME,value:i.fieldName}})}else if(i.type instanceof e.GraphQLObjectType&&!d.has(i.type.name)&&a<o){d.add(i.type.name);var r=[];l(i.type,r,v.test(i.type.name)?a:a+1);var c=i.args?Object.keys(i.args).map((n=>{var a=i.args[n];return{kind:e.Kind.ARGUMENT,value:{kind:a.kind,value:a.value},name:{kind:e.Kind.NAME,value:n}}})):[];u.push({kind:e.Kind.FIELD,selectionSet:{kind:e.Kind.SELECTION_SET,selections:r},arguments:c,name:{kind:e.Kind.NAME,value:i.fieldName}})}}))}else 1===t.length&&i.push({kind:e.Kind.FIELD,name:{kind:e.Kind.NAME,value:"__typename"}})}))};d.add(s.name);var u=n.selectionSet?[...n.selectionSet.selections]:[];return l(s,u,0),{...n,selectionSet:{kind:e.Kind.SELECTION_SET,selections:u},directives:i}}}));return{...n,query:i}},y=(n,r,s={})=>{if(e.isAbstractType(n))c.getPossibleTypes(n).forEach((e=>{y(e,r)}));else for(var d=n.getFields(),l=null,u=0;u<r.length;u++){var o=r[u];if(o.kind!==e.Kind.FRAGMENT_SPREAD)if(o.kind!==e.Kind.INLINE_FRAGMENT){if(o.kind===e.Kind.FIELD){var v=o.name.value;if(d[v]){var p=s[v]||(s[v]=n),E=m.get(p.name);E||m.set(n.name,E={});var N=t(d[v].type);if(o.arguments&&o.arguments.length){l={};for(var T=0;T<o.arguments.length;T++){var g=o.arguments[T];l[g.name.value]={value:e.valueFromASTUntyped(g.value,f),kind:g.value.kind}}}var K=l?`${v}:${i.stringifyVariables(l)}`:v;E[K]||(E[K]={type:N,args:l,fieldName:v}),o.selectionSet&&y(N,o.selectionSet.selections)}}}else y(n,o.selectionSet.selections);else{var I=a(o),S=k[I];S&&y(n,S.selectionSet.selections)}}},T=({key:n,kind:i,query:r,variables:s})=>{if("query"===i&&(E.add(n),!p.has(n))){p.add(n),f=s||{};for(var d=r.definitions.length;d--;){var l=r.definitions[d];if(l.kind===e.Kind.FRAGMENT_DEFINITION)k[a(l)]=l;else if(l.kind===e.Kind.OPERATION_DEFINITION){var u=c.getQueryType();y(t(u),l.selectionSet.selections)}}}},g=({key:e,kind:n})=>{"teardown"===n&&E.delete(e)};return e=>u(n.map(N)(n.tap(g)(n.tap(T)(e))))}; | ||
//# sourceMappingURL=urql-exchange-populate.min.js.map |
{ | ||
"name": "@urql/exchange-populate", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "An exchange that automaticcally populates the mutation selection body", | ||
"sideEffects": false, | ||
"homepage": "https://formidable.com/open-source/urql/docs/advanced/auto-populate-mutations", | ||
"bugs": "https://github.com/FormidableLabs/urql/issues", | ||
"bugs": "https://github.com/urql-graphql/urql/issues", | ||
"license": "MIT", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/FormidableLabs/urql.git", | ||
"url": "https://github.com/urql-graphql/urql.git", | ||
"directory": "exchanges/populate" | ||
@@ -16,3 +16,3 @@ }, | ||
"urql", | ||
"formidablelabs", | ||
"graphql", | ||
"exchanges" | ||
@@ -22,3 +22,3 @@ ], | ||
"module": "dist/urql-exchange-populate.mjs", | ||
"types": "dist/types/index.d.ts", | ||
"types": "dist/urql-exchange-populate.d.ts", | ||
"source": "src/index.ts", | ||
@@ -29,3 +29,3 @@ "exports": { | ||
"require": "./dist/urql-exchange-populate.js", | ||
"types": "./dist/types/index.d.ts", | ||
"types": "./dist/urql-exchange-populate.d.ts", | ||
"source": "./src/index.ts" | ||
@@ -42,16 +42,4 @@ }, | ||
], | ||
"scripts": { | ||
"test": "jest", | ||
"clean": "rimraf dist extras", | ||
"check": "tsc --noEmit", | ||
"lint": "eslint --ext=js,jsx,ts,tsx .", | ||
"build": "rollup -c ../../scripts/rollup/config.js", | ||
"prepare": "node ../../scripts/prepare/index.js", | ||
"prepublishOnly": "run-s clean build" | ||
}, | ||
"jest": { | ||
"preset": "../../scripts/jest/preset" | ||
}, | ||
"dependencies": { | ||
"@urql/core": ">=3.0.0", | ||
"@urql/core": ">=3.2.0", | ||
"wonka": "^6.0.0" | ||
@@ -63,7 +51,15 @@ }, | ||
"devDependencies": { | ||
"graphql": "^16.0.0" | ||
"graphql": "^16.0.0", | ||
"@urql/core": "3.2.0" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"scripts": { | ||
"test": "vitest --config ../../vitest.config.ts", | ||
"clean": "rimraf dist extras", | ||
"check": "tsc --noEmit", | ||
"lint": "eslint --ext=js,jsx,ts,tsx .", | ||
"build": "rollup -c ../../scripts/rollup/config.mjs" | ||
} | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
719
0
61629
2
13
Updated@urql/core@>=3.2.0