houdini 0.12.0-alpha.0 → 0.12.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +59 -9
  2. package/build/cmd/generate.js +8 -4
  3. package/build/cmd/generators/artifacts/selection.js +1 -1
  4. package/build/cmd/generators/typescript/index.js +4 -1
  5. package/build/cmd/transforms/composeQueries.d.ts +0 -7
  6. package/build/cmd/transforms/composeQueries.js +2 -3
  7. package/build/cmd/transforms/fragmentVariables.d.ts +16 -0
  8. package/build/cmd/transforms/fragmentVariables.js +61 -44
  9. package/build/cmd/transforms/list.js +1 -23
  10. package/build/cmd/transforms/paginate.d.ts +0 -34
  11. package/build/cmd/transforms/paginate.js +2 -3
  12. package/build/cmd/validators/typeCheck.js +52 -1
  13. package/build/cmd.js +855 -803
  14. package/build/runtime/cache/cache.d.ts +45 -76
  15. package/build/runtime/cache/cache.js +755 -400
  16. package/build/runtime/cache/{lists.d.ts → list.d.ts} +17 -28
  17. package/build/{runtime-cjs/cache/lists.js → runtime/cache/list.js} +71 -152
  18. package/build/runtime/cache/record.d.ts +40 -0
  19. package/build/runtime/cache/record.js +342 -0
  20. package/build/runtime/fragment.js +42 -64
  21. package/build/runtime/index.d.ts +0 -1
  22. package/build/runtime/index.js +0 -1
  23. package/build/runtime/mutation.js +1 -1
  24. package/build/runtime/network.d.ts +14 -6
  25. package/build/runtime/network.js +43 -26
  26. package/build/runtime/pagination.js +1 -3
  27. package/build/runtime/query.js +3 -5
  28. package/build/runtime/scalars.js +15 -3
  29. package/build/runtime/types.d.ts +0 -2
  30. package/build/runtime-cjs/cache/cache.d.ts +45 -76
  31. package/build/runtime-cjs/cache/cache.js +755 -400
  32. package/build/runtime-cjs/cache/{lists.d.ts → list.d.ts} +17 -28
  33. package/build/{runtime/cache/lists.js → runtime-cjs/cache/list.js} +71 -152
  34. package/build/runtime-cjs/cache/record.d.ts +40 -0
  35. package/build/runtime-cjs/cache/record.js +342 -0
  36. package/build/runtime-cjs/fragment.js +42 -64
  37. package/build/runtime-cjs/index.d.ts +0 -1
  38. package/build/runtime-cjs/index.js +0 -1
  39. package/build/runtime-cjs/mutation.js +1 -1
  40. package/build/runtime-cjs/network.d.ts +14 -6
  41. package/build/runtime-cjs/network.js +43 -26
  42. package/build/runtime-cjs/pagination.js +1 -3
  43. package/build/runtime-cjs/query.js +3 -5
  44. package/build/runtime-cjs/scalars.js +15 -3
  45. package/build/runtime-cjs/types.d.ts +0 -2
  46. package/build/runtime-esm/cache/cache.d.ts +45 -76
  47. package/build/runtime-esm/cache/cache.js +512 -310
  48. package/build/runtime-esm/fragment.js +40 -65
  49. package/build/runtime-esm/index.d.ts +0 -1
  50. package/build/runtime-esm/index.js +0 -1
  51. package/build/runtime-esm/mutation.js +1 -1
  52. package/build/runtime-esm/network.d.ts +14 -6
  53. package/build/runtime-esm/network.js +29 -13
  54. package/build/runtime-esm/pagination.js +1 -3
  55. package/build/runtime-esm/query.js +3 -5
  56. package/build/runtime-esm/scalars.js +15 -3
  57. package/build/runtime-esm/types.d.ts +0 -2
  58. package/cmd/generate.ts +9 -5
  59. package/cmd/generators/artifacts/selection.ts +3 -1
  60. package/cmd/generators/typescript/index.ts +6 -1
  61. package/cmd/generators/typescript/typescript.test.ts +14 -14
  62. package/cmd/transforms/composeQueries.ts +3 -3
  63. package/cmd/transforms/fragmentVariables.test.ts +9 -9
  64. package/cmd/transforms/fragmentVariables.ts +72 -55
  65. package/cmd/transforms/list.ts +1 -43
  66. package/cmd/transforms/lists.test.ts +1 -68
  67. package/cmd/transforms/paginate.ts +1 -1
  68. package/cmd/validators/typeCheck.test.ts +18 -2
  69. package/cmd/validators/typeCheck.ts +57 -1
  70. package/package.json +3 -3
  71. package/runtime/cache/cache.ts +670 -420
  72. package/runtime/cache/{lists.ts → list.ts} +47 -124
  73. package/runtime/cache/record.ts +255 -0
  74. package/runtime/cache/tests/{subscriptions.test.ts → cache.test.ts} +266 -203
  75. package/runtime/cache/tests/gc.test.ts +18 -63
  76. package/runtime/cache/tests/list.test.ts +153 -193
  77. package/runtime/cache/tests/{availability.test.ts → policy.test.ts} +8 -9
  78. package/runtime/cache/tests/scalars.test.ts +5 -5
  79. package/runtime/fragment.ts +41 -74
  80. package/runtime/index.ts +0 -1
  81. package/runtime/mutation.ts +1 -1
  82. package/runtime/network.ts +63 -26
  83. package/runtime/pagination.ts +1 -6
  84. package/runtime/query.ts +6 -5
  85. package/runtime/scalars.test.ts +130 -0
  86. package/runtime/scalars.ts +17 -3
  87. package/runtime/types.ts +0 -2
  88. package/build/runtime/cache/gc.d.ts +0 -9
  89. package/build/runtime/cache/gc.js +0 -96
  90. package/build/runtime/cache/storage.d.ts +0 -86
  91. package/build/runtime/cache/storage.js +0 -535
  92. package/build/runtime/cache/stuff.d.ts +0 -6
  93. package/build/runtime/cache/stuff.js +0 -98
  94. package/build/runtime/cache/subscription.d.ts +0 -29
  95. package/build/runtime/cache/subscription.js +0 -384
  96. package/build/runtime/proxy.d.ts +0 -6
  97. package/build/runtime/proxy.js +0 -52
  98. package/build/runtime-cjs/cache/gc.d.ts +0 -9
  99. package/build/runtime-cjs/cache/gc.js +0 -96
  100. package/build/runtime-cjs/cache/storage.d.ts +0 -86
  101. package/build/runtime-cjs/cache/storage.js +0 -535
  102. package/build/runtime-cjs/cache/stuff.d.ts +0 -6
  103. package/build/runtime-cjs/cache/stuff.js +0 -98
  104. package/build/runtime-cjs/cache/subscription.d.ts +0 -29
  105. package/build/runtime-cjs/cache/subscription.js +0 -384
  106. package/build/runtime-cjs/proxy.d.ts +0 -6
  107. package/build/runtime-cjs/proxy.js +0 -52
  108. package/build/runtime-esm/cache/gc.d.ts +0 -9
  109. package/build/runtime-esm/cache/gc.js +0 -38
  110. package/build/runtime-esm/cache/lists.d.ts +0 -46
  111. package/build/runtime-esm/cache/lists.js +0 -259
  112. package/build/runtime-esm/cache/storage.d.ts +0 -86
  113. package/build/runtime-esm/cache/storage.js +0 -370
  114. package/build/runtime-esm/cache/stuff.d.ts +0 -6
  115. package/build/runtime-esm/cache/stuff.js +0 -59
  116. package/build/runtime-esm/cache/subscription.d.ts +0 -29
  117. package/build/runtime-esm/cache/subscription.js +0 -217
  118. package/build/runtime-esm/proxy.d.ts +0 -6
  119. package/build/runtime-esm/proxy.js +0 -25
  120. package/runtime/cache/gc.ts +0 -53
  121. package/runtime/cache/storage.ts +0 -489
  122. package/runtime/cache/stuff.ts +0 -77
  123. package/runtime/cache/subscription.ts +0 -300
  124. package/runtime/cache/tests/keys.test.ts +0 -34
  125. package/runtime/cache/tests/storage.test.ts +0 -383
  126. package/runtime/proxy.ts +0 -28
package/README.md CHANGED
@@ -42,7 +42,7 @@ for the generation of an incredibly lean GraphQL abstraction for your applicatio
42
42
  1. [Fetching Data](#fetching-data)
43
43
  1. [Query variables and page data](#query-variables-and-page-data)
44
44
  1. [Loading State](#loading-state)
45
- 1. [Additional Logic](#additional-logic)
45
+ 1. [Hooks](#load-hooks)
46
46
  1. [Refetching Data](#refetching-data)
47
47
  1. [Cache policy](#cache-policy)
48
48
  1. [Data Retention](#data-retention)
@@ -69,7 +69,7 @@ for the generation of an incredibly lean GraphQL abstraction for your applicatio
69
69
  1. [Persisted Queries](#persisted-queries)
70
70
  1. [Notes, Constraints, and Conventions](#%EF%B8%8Fnotes-constraints-and-conventions)
71
71
 
72
- ## 🕹️  Example
72
+ ## 🕹  Example
73
73
 
74
74
  A demo can be found in the <a href='./example'>example directory</a>.
75
75
 
@@ -123,7 +123,12 @@ import houdini from 'houdini-preprocess'
123
123
  alias: {
124
124
  $houdini: path.resolve('.', '$houdini')
125
125
  }
126
- }
126
+ },
127
+ server: {
128
+ fs: {
129
+ allow: ['.'],
130
+ },
131
+ },
127
132
  }
128
133
  }
129
134
  }
@@ -327,23 +332,30 @@ the result of query:
327
332
  {/if}
328
333
  ```
329
334
 
330
- ### Additional logic
335
+ ### Load Hooks
331
336
 
332
337
  Sometimes you will need to add additional logic to a component's query. For example, you might want to
333
338
  check if the current session is valid before a query is sent to the server. In order to support this,
334
- houdini will look for a function called `onLoad` defined in the module context which can be used to perform
335
- any logic you need. If you return a value from this function, it will be passed as props to your component:
339
+ houdini will look for hook functions defined in the module context which can be used to perform
340
+ any logic you need.
341
+
342
+ #### `beforeLoad`
343
+
344
+ Called before Houdini executes load queries against the server. You can expect the same
345
+ arguments as SvelteKit's [`load`](https://kit.svelte.dev/docs#loading) hook.
346
+
347
+ If you return a value from this function, it will be passed as props to your component.
336
348
 
337
349
  ```svelte
338
350
  <script context="module">
339
351
  // It has access to the same arguments and this.error this.redirect as the variable functions
340
- export function onLoad({page, session}){
352
+ export function beforeLoad({page, session}){
341
353
  if(!session.authenticated){
342
354
  return this.redirect(302, '/login')
343
355
  }
344
356
 
345
- return {
346
- message: "There are this many items"
357
+ return {
358
+ message: "There are this many items"
347
359
  }
348
360
  }
349
361
  </script>
@@ -366,6 +378,42 @@ any logic you need. If you return a value from this function, it will be passed
366
378
  {message}: {$data.items.length}
367
379
  ```
368
380
 
381
+ #### `afterLoad`
382
+
383
+ Called after Houdini executes load queries against the server. You can expect the same
384
+ arguments as SvelteKit's [`load`](https://kit.svelte.dev/docs#loading) hook, plus an additional
385
+ `data` property referencing query result data.
386
+
387
+ If you return a value from this function, it will be passed as props to your component.
388
+
389
+ ```svelte
390
+ <script context="module">
391
+ export function MyProfileVariables({ page: { params: { id } } }) {
392
+ return { id }
393
+ }
394
+ export function afterLoad({ data }){
395
+ if(!data.MyProfile){
396
+ return this.error(404)
397
+ }
398
+ }
399
+ </script>
400
+
401
+ <script>
402
+ import { query, graphql } from '$houdini'
403
+
404
+ // load the items
405
+ const { data } = query(graphql`
406
+ query MyProfile {
407
+ profile(id) {
408
+ name
409
+ }
410
+ }
411
+ `)
412
+ </script>
413
+
414
+ Hello I'm {$data.profile.name}
415
+ ```
416
+
369
417
  ### Refetching Data
370
418
 
371
419
  Refetching data is done with the `refetch` function provided from the result of a query:
@@ -572,6 +620,8 @@ query AllUsers {
572
620
  }
573
621
  }
574
622
  ```
623
+ > Keep in mind, if you are using fragment variables inside of a field flagged for
624
+ > list operations, you'll have to pass a value for the variable when performing the operation
575
625
 
576
626
  ## 📝&nbsp;&nbsp;Mutations
577
627
 
@@ -107,13 +107,17 @@ exports.runPipeline = function (config, docs) { return __awaiter(void 0, void 0,
107
107
  // we need to create the runtime folder structure
108
108
  _a.sent();
109
109
  return [4 /*yield*/, houdini_common_1.runPipeline(config, [
110
- transforms.internalSchema,
111
- transforms.list,
112
- transforms.addID,
113
110
  validators.typeCheck,
114
- transforms.typename,
115
111
  validators.uniqueNames,
116
112
  validators.noIDAlias,
113
+ transforms.internalSchema,
114
+ transforms.addID,
115
+ transforms.typename,
116
+ // list transform must go before fragment variables
117
+ // so that the mutation fragments are defined before they get mixed in
118
+ transforms.list,
119
+ // paginate transform needs to go before fragmentVariables
120
+ // so that the variable definitions get hashed
117
121
  transforms.paginate,
118
122
  transforms.fragmentVariables,
119
123
  transforms.composeQueries,
@@ -65,7 +65,7 @@ function selection(_a) {
65
65
  // look up the fragment definition
66
66
  var fragmentDefinition = document.document.definitions.find(function (defn) { return defn.kind === 'FragmentDefinition' && defn.name.value === field.name.value; });
67
67
  if (!fragmentDefinition) {
68
- throw new Error('Could not find definition for fragment ' + field.name.value);
68
+ throw new Error('selection: could not find definition for fragment ' + field.name.value);
69
69
  }
70
70
  // merge the fragments selection into ours
71
71
  object = utils_1.deepMerge(object, selection({
@@ -191,7 +191,10 @@ function generateOperationTypeDefs(config, body, definition, selections, visited
191
191
  types_1.readonlyProperty(AST.tsPropertySignature(AST.stringLiteral('input'), AST.tsTypeAnnotation(hasInputs
192
192
  ? AST.tsTypeReference(AST.identifier(inputTypeName))
193
193
  : AST.tsNullKeyword()))),
194
- types_1.readonlyProperty(AST.tsPropertySignature(AST.stringLiteral('result'), AST.tsTypeAnnotation(AST.tsTypeReference(AST.identifier(shapeTypeName))))),
194
+ types_1.readonlyProperty(AST.tsPropertySignature(AST.stringLiteral('result'), AST.tsTypeAnnotation(AST.tsUnionType([
195
+ AST.tsTypeReference(AST.identifier(shapeTypeName)),
196
+ AST.tsUndefinedKeyword(),
197
+ ])))),
195
198
  ]))),
196
199
  // export the type that describes the result
197
200
  AST.exportNamedDeclaration(AST.tsTypeAliasDeclaration(AST.identifier(shapeTypeName), inlineType_1.inlineType({
@@ -8,10 +8,3 @@ export declare type FragmentDependency = {
8
8
  };
9
9
  export default function includeFragmentDefinitions(config: Config, documents: CollectedGraphQLDocument[]): Promise<void>;
10
10
  export declare function collectFragments(config: Config, docs: CollectedGraphQLDocument[]): Record<string, FragmentDependency>;
11
- export declare function flattenFragments(operation: {
12
- requiredFragments: Array<string>;
13
- }, fragments: {
14
- [name: string]: {
15
- requiredFragments: Array<string>;
16
- };
17
- }): Array<string>;
@@ -78,7 +78,7 @@ var __spread = (this && this.__spread) || function () {
78
78
  return ar;
79
79
  };
80
80
  Object.defineProperty(exports, "__esModule", { value: true });
81
- exports.flattenFragments = exports.collectFragments = void 0;
81
+ exports.collectFragments = void 0;
82
82
  // externals
83
83
  var graphql_1 = require("graphql");
84
84
  // includeFragmentDefinitions adds any referenced fragments to operations
@@ -199,7 +199,7 @@ function flattenFragments(operation, fragments) {
199
199
  // grab the referenced fragment
200
200
  var targetFragment = fragments[nextFragment];
201
201
  if (!targetFragment) {
202
- throw new Error('Could not find definition for fragment ' + nextFragment);
202
+ throw new Error('compose: could not find definition for fragment ' + nextFragment);
203
203
  }
204
204
  // add this fragments dependents to the pile
205
205
  remaining.push.apply(remaining, __spread(targetFragment.requiredFragments));
@@ -207,4 +207,3 @@ function flattenFragments(operation, fragments) {
207
207
  // we're done
208
208
  return __spread(frags);
209
209
  }
210
- exports.flattenFragments = flattenFragments;
@@ -1,7 +1,18 @@
1
1
  import { Config } from 'houdini-common';
2
2
  import * as graphql from 'graphql';
3
3
  import { CollectedGraphQLDocument } from '../types';
4
+ import { FragmentDependency } from './composeQueries';
4
5
  export default function fragmentVariables(config: Config, documents: CollectedGraphQLDocument[]): Promise<void>;
6
+ declare type ValueMap = Record<string, graphql.ValueNode>;
7
+ export declare function inlineFragmentArgs({ config, fragmentDefinitions, document, generatedFragments, visitedFragments, scope, newName, }: {
8
+ config: Config;
9
+ fragmentDefinitions: Record<string, FragmentDependency>;
10
+ document: graphql.ASTNode;
11
+ generatedFragments: Record<string, graphql.FragmentDefinitionNode>;
12
+ visitedFragments: Set<string>;
13
+ scope: ValueMap | undefined | null;
14
+ newName?: string;
15
+ }): any;
5
16
  export declare function withArguments(config: Config, node: graphql.FragmentSpreadNode): graphql.ArgumentNode[];
6
17
  export declare type FragmentArgument = {
7
18
  name: string;
@@ -10,3 +21,8 @@ export declare type FragmentArgument = {
10
21
  defaultValue: graphql.ValueNode | null;
11
22
  };
12
23
  export declare function fragmentArguments(config: Config, definition: graphql.FragmentDefinitionNode): FragmentArgument[];
24
+ export declare function collectWithArguments(config: Config, node: graphql.FragmentSpreadNode, scope?: ValueMap | null): {
25
+ args: ValueMap | null;
26
+ hash: string;
27
+ };
28
+ export {};
@@ -97,7 +97,7 @@ var __spread = (this && this.__spread) || function () {
97
97
  return ar;
98
98
  };
99
99
  Object.defineProperty(exports, "__esModule", { value: true });
100
- exports.fragmentArguments = exports.withArguments = void 0;
100
+ exports.collectWithArguments = exports.fragmentArguments = exports.withArguments = exports.inlineFragmentArgs = void 0;
101
101
  var graphql = __importStar(require("graphql"));
102
102
  var composeQueries_1 = require("./composeQueries");
103
103
  var utils_1 = require("../utils");
@@ -105,11 +105,10 @@ var types_1 = require("../../runtime/types");
105
105
  var GraphqlKinds = graphql.Kind;
106
106
  // fragmentVariables transforms fragment spreads with variables into something the server can use
107
107
  function fragmentVariables(config, documents) {
108
- var _a;
109
108
  return __awaiter(this, void 0, void 0, function () {
110
- var fragments, generatedFragments, visitedFragments, documents_1, documents_1_1, doc_1, operation, rootScope, doc;
111
- var e_1, _b;
112
- return __generator(this, function (_c) {
109
+ var fragments, generatedFragments, visitedFragments, documents_1, documents_1_1, doc_1, operation, doc;
110
+ var e_1, _a;
111
+ return __generator(this, function (_b) {
113
112
  fragments = composeQueries_1.collectFragments(config, documents);
114
113
  generatedFragments = {};
115
114
  visitedFragments = new Set();
@@ -125,16 +124,6 @@ function fragmentVariables(config, documents) {
125
124
  if (!operation) {
126
125
  continue;
127
126
  }
128
- rootScope = ((_a = operation.variableDefinitions) === null || _a === void 0 ? void 0 : _a.reduce(function (scope, definition) {
129
- var _a;
130
- return (__assign(__assign({}, scope), (_a = {}, _a[definition.variable.name.value] = {
131
- kind: 'Variable',
132
- name: {
133
- kind: 'Name',
134
- value: definition.variable.name.value,
135
- },
136
- }, _a)));
137
- }, {})) || {};
138
127
  // inline any fragment arguments in the document
139
128
  doc_1.document = inlineFragmentArgs({
140
129
  config: config,
@@ -142,14 +131,14 @@ function fragmentVariables(config, documents) {
142
131
  document: doc_1.document,
143
132
  generatedFragments: generatedFragments,
144
133
  visitedFragments: visitedFragments,
145
- scope: rootScope,
134
+ scope: null,
146
135
  });
147
136
  }
148
137
  }
149
138
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
150
139
  finally {
151
140
  try {
152
- if (documents_1_1 && !documents_1_1.done && (_b = documents_1.return)) _b.call(documents_1);
141
+ if (documents_1_1 && !documents_1_1.done && (_a = documents_1.return)) _a.call(documents_1);
153
142
  }
154
143
  finally { if (e_1) throw e_1.error; }
155
144
  }
@@ -172,37 +161,22 @@ function fragmentVariables(config, documents) {
172
161
  exports.default = fragmentVariables;
173
162
  function inlineFragmentArgs(_a) {
174
163
  var config = _a.config, fragmentDefinitions = _a.fragmentDefinitions, document = _a.document, generatedFragments = _a.generatedFragments, visitedFragments = _a.visitedFragments, scope = _a.scope, newName = _a.newName;
164
+ // if the scope is null, use the root-level scope defined by the document's
165
+ // operation definition
166
+ if (!scope) {
167
+ scope = operationScope(document.definitions.find(function (_a) {
168
+ var kind = _a.kind;
169
+ return kind === GraphqlKinds.OPERATION_DEFINITION;
170
+ }));
171
+ }
175
172
  // look up the arguments for the fragment
176
173
  var definitionArgs = fragmentArguments(config, document).reduce(function (acc, arg) {
177
174
  var _a;
178
175
  return (__assign(__assign({}, acc), (_a = {}, _a[arg.name] = arg, _a)));
179
176
  }, {});
180
177
  var result = graphql.visit(document, {
181
- Argument: function (node) {
182
- // look at the arguments value to see if its a variable
183
- var value = node.value;
184
- if (value.kind !== 'Variable') {
185
- return;
186
- }
187
- // if there's no scope we can't evaluate it
188
- if (!scope) {
189
- throw new Error(node.name.value +
190
- ' is not defined in the current scope: ' +
191
- JSON.stringify(scope));
192
- }
193
- // is the variable in scope
194
- var newValue = scope[value.name.value];
195
- // if it is just use it
196
- if (newValue) {
197
- return __assign(__assign({}, node), { value: newValue });
198
- }
199
- // if the argument is required
200
- if (definitionArgs[value.name.value] && definitionArgs[value.name.value].required) {
201
- throw new Error('Missing value for required arg: ' + value.name.value);
202
- }
203
- // if we got this far, theres no value for a non-required arg, remove the node
204
- return null;
205
- },
178
+ // every time we run into a fragment spread we might need to replace it
179
+ // with a version that incorporates the current scope's variable values
206
180
  FragmentSpread: function (node) {
207
181
  var e_2, _a;
208
182
  // look at the fragment spread to see if there are any default arguments
@@ -257,7 +231,8 @@ function inlineFragmentArgs(_a) {
257
231
  return definition.kind === 'FragmentDefinition' &&
258
232
  definition.name.value === node.name.value;
259
233
  });
260
- // remove the element from the list
234
+ // keep walking down the referenced fragment's selection
235
+ // and replace the definition in the document
261
236
  var localDefinitions = __spread(doc.document.definitions);
262
237
  localDefinitions.splice(definitionIndex, 1);
263
238
  localDefinitions.push(inlineFragmentArgs({
@@ -281,8 +256,35 @@ function inlineFragmentArgs(_a) {
281
256
  }
282
257
  }
283
258
  },
259
+ // look at every time something is used as an argument
260
+ Argument: function (node) {
261
+ // if the argument is a variable we need to expand it to its value (passed from the parent)
262
+ var value = node.value;
263
+ if (value.kind !== 'Variable') {
264
+ return;
265
+ }
266
+ // if there's no scope we can't evaluate it
267
+ if (!scope) {
268
+ throw new Error(node.name.value +
269
+ ' is not defined in the current scope: ' +
270
+ JSON.stringify(scope));
271
+ }
272
+ // is the variable in scope
273
+ var newValue = scope[value.name.value];
274
+ // if it is just use it
275
+ if (newValue) {
276
+ return __assign(__assign({}, node), { value: newValue });
277
+ }
278
+ // if the argument is required
279
+ if (definitionArgs[value.name.value] && definitionArgs[value.name.value].required) {
280
+ throw new Error('Missing value for required arg: ' + value.name.value);
281
+ }
282
+ // if we got this far, theres no value for a non-required arg, remove the node
283
+ return null;
284
+ },
284
285
  });
285
- // if we are supposed to change the name
286
+ // if we computed a new name for the fragment (because we got here as part of analyzing a fragment
287
+ // spread with @with), we need to change the name of the fragment
286
288
  if (newName) {
287
289
  // the new name for the document
288
290
  result.name = {
@@ -292,6 +294,7 @@ function inlineFragmentArgs(_a) {
292
294
  }
293
295
  return result;
294
296
  }
297
+ exports.inlineFragmentArgs = inlineFragmentArgs;
295
298
  function withArguments(config, node) {
296
299
  var _a;
297
300
  var withDirectives = (_a = node.directives) === null || _a === void 0 ? void 0 : _a.filter(function (directive) { return directive.name.value === config.withDirective; });
@@ -407,3 +410,17 @@ function collectWithArguments(config, node, scope) {
407
410
  hash: '_' + utils_1.murmurHash(JSON.stringify(args)),
408
411
  };
409
412
  }
413
+ exports.collectWithArguments = collectWithArguments;
414
+ function operationScope(operation) {
415
+ var _a;
416
+ return (((_a = operation.variableDefinitions) === null || _a === void 0 ? void 0 : _a.reduce(function (scope, definition) {
417
+ var _a;
418
+ return (__assign(__assign({}, scope), (_a = {}, _a[definition.variable.name.value] = {
419
+ kind: 'Variable',
420
+ name: {
421
+ kind: 'Name',
422
+ value: definition.variable.name.value,
423
+ },
424
+ }, _a)));
425
+ }, {})) || {});
426
+ }
@@ -105,7 +105,6 @@ var graphql = __importStar(require("graphql"));
105
105
  var types_1 = require("../types");
106
106
  var utils_1 = require("../utils");
107
107
  var types_2 = require("../../runtime/types");
108
- var paginate_1 = require("./paginate");
109
108
  // addListFragments adds fragments for the fields tagged with @list
110
109
  function addListFragments(config, documents) {
111
110
  return __awaiter(this, void 0, void 0, function () {
@@ -118,7 +117,7 @@ function addListFragments(config, documents) {
118
117
  doc.document = graphql.visit(doc.document, {
119
118
  Directive: function (node, key, parent, path, ancestors) {
120
119
  var _a;
121
- // if we found a @list applied (old applications will call this @connection)
120
+ // if we found a @list applied (or a @paginate which implies a @list )
122
121
  if ([config.listDirective, config.paginateDirective].includes(node.name.value)) {
123
122
  // look up the name passed to the directive
124
123
  var nameArg = (_a = node.arguments) === null || _a === void 0 ? void 0 : _a.find(function (arg) { return arg.name.value === 'name'; });
@@ -178,27 +177,6 @@ function addListFragments(config, documents) {
178
177
  }
179
178
  }
180
179
  },
181
- Field: function (node, key, parent, path, ancestors) {
182
- var _a;
183
- // if the is marked with @list and is a connection, we need to make sure that we ask for
184
- // the cursor fields
185
- if (!((_a = node.directives) === null || _a === void 0 ? void 0 : _a.find(function (directive) { return directive.name.value === config.listDirective; }))) {
186
- return;
187
- }
188
- // the field is a list, is it a connection?
189
- // look up the parent's type
190
- var parentType = houdini_common_1.parentTypeFromAncestors(config.schema, ancestors);
191
- // a non-connection list can just use the selection set of the tagged field
192
- // but if this is a connection tagged with list we need to use the selection
193
- // of the edges.node field
194
- var targetField = node;
195
- var targetFieldDefinition = parentType.getFields()[targetField.name.value];
196
- var connection = connectionSelection(config, targetFieldDefinition, houdini_common_1.parentTypeFromAncestors(config.schema, ancestors), node.selectionSet).connection;
197
- // if the field is a connection, add the cursor
198
- if (connection) {
199
- return __assign(__assign({}, node), { selectionSet: __assign(__assign({}, node.selectionSet), { selections: __spread(node.selectionSet.selections, paginate_1.pageInfoSelection) }) });
200
- }
201
- },
202
180
  });
203
181
  };
204
182
  try {
@@ -1,37 +1,3 @@
1
1
  import { Config } from 'houdini-common';
2
2
  import { CollectedGraphQLDocument } from '../types';
3
3
  export default function paginate(config: Config, documents: CollectedGraphQLDocument[]): Promise<void>;
4
- export declare const pageInfoSelection: {
5
- kind: string;
6
- name: {
7
- kind: string;
8
- value: string;
9
- };
10
- selectionSet: {
11
- kind: string;
12
- selections: ({
13
- kind: string;
14
- name: {
15
- kind: string;
16
- value: string;
17
- };
18
- selectionSet?: undefined;
19
- } | {
20
- kind: string;
21
- name: {
22
- kind: string;
23
- value: string;
24
- };
25
- selectionSet: {
26
- kind: string;
27
- selections: {
28
- kind: string;
29
- name: {
30
- kind: string;
31
- value: string;
32
- };
33
- }[];
34
- };
35
- })[];
36
- };
37
- }[];
@@ -97,7 +97,6 @@ var __values = (this && this.__values) || function(o) {
97
97
  throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
98
98
  };
99
99
  Object.defineProperty(exports, "__esModule", { value: true });
100
- exports.pageInfoSelection = void 0;
101
100
  // externals
102
101
  var graphql = __importStar(require("graphql"));
103
102
  var houdini_common_1 = require("houdini-common");
@@ -192,7 +191,7 @@ function paginate(config, documents) {
192
191
  ? // no need to add any fields to the selection if we're dealing with offset pagination
193
192
  node.selectionSet
194
193
  : // add the page info if we are dealing with cursor-based pagination
195
- __assign(__assign({}, node.selectionSet), { selections: __spread(node.selectionSet.selections, exports.pageInfoSelection) }) });
194
+ __assign(__assign({}, node.selectionSet), { selections: __spread(node.selectionSet.selections, pageInfoSelection) }) });
196
195
  },
197
196
  });
198
197
  // if we saw the paginate directive we need to add arguments to the fragment or query that contain the
@@ -611,7 +610,7 @@ function objectNode(_a) {
611
610
  }
612
611
  return node;
613
612
  }
614
- exports.pageInfoSelection = [
613
+ var pageInfoSelection = [
615
614
  {
616
615
  kind: 'Field',
617
616
  name: {
@@ -247,6 +247,11 @@ function typeCheck(config, docs) {
247
247
  var targetField = ancestors[ancestors.length - 1];
248
248
  var targetFieldDefinition = parentType.getFields()[targetField.name.value];
249
249
  var type = list_1.connectionSelection(config, targetFieldDefinition, houdini_common_1.parentTypeFromAncestors(config.schema, ancestors), targetField.selectionSet).type;
250
+ // make sure there is an id field
251
+ if (!type.getFields()['id']) {
252
+ errors.push(new types_1.HoudiniErrorTodo("@" + config.listDirective + " can only be applied to types with an id field."));
253
+ return;
254
+ }
250
255
  // add the list to the list
251
256
  lists.push(listName);
252
257
  listTypes.push(type.name);
@@ -265,6 +270,10 @@ function typeCheck(config, docs) {
265
270
  }
266
271
  finally { if (e_1) throw e_1.error; }
267
272
  }
273
+ // if we got errors
274
+ if (errors.length > 0) {
275
+ throw errors;
276
+ }
268
277
  rules = __spread(graphql.specifiedRules).filter(
269
278
  // remove rules that conflict with houdini
270
279
  function (rule) {
@@ -302,7 +311,9 @@ function typeCheck(config, docs) {
302
311
  // validate any fragment arguments
303
312
  validateFragmentArguments(config, fragments),
304
313
  // make sure there are pagination args on fields marked with @paginate
305
- paginateArgs(config));
314
+ paginateArgs(config),
315
+ // make sure every argument defined in a fragment is used
316
+ noUnusedFragmentArguments(config));
306
317
  try {
307
318
  for (docs_2 = __values(docs), docs_2_1 = docs_2.next(); !docs_2_1.done; docs_2_1 = docs_2.next()) {
308
319
  _a = docs_2_1.value, filename = _a.filename, parsed = _a.document;
@@ -659,6 +670,46 @@ function paginateArgs(config) {
659
670
  };
660
671
  };
661
672
  }
673
+ function noUnusedFragmentArguments(config) {
674
+ return function (ctx) {
675
+ // if we run into a fragment definition with arguments we need to make sure every argument is used
676
+ var args = new Set();
677
+ return {
678
+ // when we first see a fragment definition
679
+ enter: {
680
+ FragmentDefinition: function (node) {
681
+ var e_7, _a;
682
+ var _b;
683
+ var definitionArguments = (_b = node.directives) === null || _b === void 0 ? void 0 : _b.filter(function (directive) { return directive.name.value === config.argumentsDirective; }).flatMap(function (directive) { return directive.arguments; });
684
+ try {
685
+ for (var _c = __values((definitionArguments === null || definitionArguments === void 0 ? void 0 : definitionArguments.map(function (arg) { return arg === null || arg === void 0 ? void 0 : arg.name.value; })) || []), _d = _c.next(); !_d.done; _d = _c.next()) {
686
+ var arg = _d.value;
687
+ args.add(arg);
688
+ }
689
+ }
690
+ catch (e_7_1) { e_7 = { error: e_7_1 }; }
691
+ finally {
692
+ try {
693
+ if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
694
+ }
695
+ finally { if (e_7) throw e_7.error; }
696
+ }
697
+ },
698
+ Variable: function (node) {
699
+ args.delete(node.name.value);
700
+ },
701
+ },
702
+ leave: {
703
+ // once we're done with the definition make sure we used everything
704
+ FragmentDefinition: function (node) {
705
+ if (args.size > 0) {
706
+ ctx.reportError(new graphql.GraphQLError('Encountered unused fragment arguments: ' + __spread(args).join(',')));
707
+ }
708
+ },
709
+ },
710
+ };
711
+ };
712
+ }
662
713
  function nodeDirectives(config, directives) {
663
714
  var queryType = config.schema.getQueryType();
664
715
  var possibleNodes = [(queryType === null || queryType === void 0 ? void 0 : queryType.name) || ''];